home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1995 April / Internet Tools.iso / infoserv / gopher / mvs / gopher.ggmvs.distrib.cntl.v3r1.Z / gopher.ggmvs.distrib.cntl.v3r1
Encoding:
Text File  |  1994-01-16  |  658.7 KB  |  19,821 lines

  1. //JOBNAME JOB ACCOUNT,'NAME'
  2. //*------------------------------------------------------------------*/
  3. //*                                                                  */
  4. //* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1993    */
  5. //*                                                                  */
  6. //* This software is provided on an "AS IS" basis. All warranties,   */
  7. //* including the implied warranties of merchantability and fitness, */
  8. //* are expressly denied.                                            */
  9. //*                                                                  */
  10. //* Provided this copyright notice is included, this software may    */
  11. //* be freely distributed and not offered for sale.                  */
  12. //*                                                                  */
  13. //* Changes or modifications may be made and used only by the maker  */
  14. //* of same, and not further distributed. Such modifications should  */
  15. //* be mailed to the author for consideration for addition to the    */
  16. //* software and incorporation in subsequent releases.               */
  17. //*                                                                  */
  18. //*------------------------------------------------------------------*/
  19. //*
  20. //*    GOPHER - MVS Gopher Client and Server
  21. //*
  22. //*  Version: 3  Release: 1
  23. //*
  24. //* Author: Steve Bacher <seb@draper.com>
  25. //*
  26. //* Date: 16 Jan 1994
  27. //*
  28. //*-------------------------------------------------------------------
  29. //*
  30. //* This job creates the distribution libraries (PDS's).
  31. //*
  32. //* Run this JCL to create the PDS's, after customizing to suit.
  33. //* (Obviously, put in a good JOB statement first.)
  34. //* To customize the JCL, change the defaults on the //MDLOAD PROC
  35. //* statement to your liking, particularly the PREFIX default.
  36. //* You might also want to change the final qualifiers of the PDS's
  37. //* created - to do this, find the // EXEC MDLOAD statements and
  38. //* change the value of the TO parameter.
  39. //*
  40. //* See the $$README file (of the CNTL PDS, first in this stream)
  41. //* for the rest of the installation instructions.
  42. //*
  43. //MDLOAD PROC CLS='*',BS='6160',U='3380',V='',
  44. //      TRK1='60',TRK2='10',DIR='35',RLSE='RLSE',
  45. //      PREFIX='GOPHER.INSTALL.'
  46. //*
  47. //IEBUPDTE EXEC PGM=IEBUPDTE,PARM=NEW
  48. //SYSPRINT DD SYSOUT=&CLS
  49. //SYSUT2 DD DISP=(NEW,CATLG,DELETE),DSN=&PREFIX.&TO,
  50. //  DCB=(RECFM=FB,LRECL=80,BLKSIZE=&BS),
  51. //  SPACE=(TRK,(&TRK1,&TRK2,&DIR),&RLSE),UNIT=&U,VOL=SER=&V
  52. //*
  53. //  PEND
  54. //*
  55. //CNTL     EXEC MDLOAD,BS='6160',TRK1='10',TRK2='1',TO='CNTL'
  56. //SYSIN    DD   DATA,DLM='?!'
  57. ./ ADD NAME=$$README
  58.  
  59. ------------------------------------------------------------------------
  60.  
  61.  Copyright (c) The Charles Stark Draper Laboratory, Inc.,1992,1993,1994
  62.  
  63.  MVS Gopher Server originally by Shawn Hart (Univ. of Delaware).
  64.  
  65.  This software is provided on an "AS IS" basis.  All warranties,
  66.  including the implied warranties of merchantability and fitness,
  67.  are expressly denied.
  68.  
  69.  Provided this copyright notice is included, this software may
  70.  be freely distributed and not offered for sale.
  71.  
  72.  Changes or modifications may be made and used only by the maker
  73.  of same, and not further distributed.  Such modifications should
  74.  be mailed to the author for consideration for addition to the
  75.  software and incorporation in subsequent releases.
  76.  
  77. ------------------------------------------------------------------------
  78.  
  79.  MVS Gopher Client
  80.  
  81.  Original Author:          Steve Bacher  <seb@draper.com>
  82.  
  83.  MVS Gopher Server
  84.  
  85.  Original Author:          Shawn Hart    <shart@indial1.io.com>
  86.  
  87.  Various enhancements and customizations to both the client and the
  88.  server have been contributed by:
  89.  
  90.     Steve Bacher   <seb@draper.com>
  91.     Lou Joseph     <cwmy5c@irishmvs.cc.nd.edu>
  92.     Denis DeLaRoca <csp1dwd@mvs.oac.ucla.edu>
  93.     Dwight Cook    <sysdc@uokmvsa.backbone.uoknor.edu>
  94.     Rachna Agrawal <rachna@clemson.clemson.edu>
  95.  
  96. ------------------------------------------------------------------------
  97.  
  98.  Contents of PDS's belonging to Gopher distribution:
  99.  
  100.  Member     PDS Type    Description
  101.  
  102.  $$README   CNTL        This file
  103.  $CHANGES   CNTL        Changes since the last release
  104.  ACCESS     CNTL        Sample server access file
  105.  ALLOAD     CNTL        JCL to allocate additional Gopher libraries
  106.  COMPILE    CNTL        JCL to compile *** SOURCE DISTRIBUTION ONLY ***
  107.  GOPHERD    CNTL        JCL to run the GOPHER server in batch (No TSO)
  108.  GOPHERT    CNTL        JCL to run the GOPHER server in batch (w. TSO)
  109.  HELP       CNTL        TSO Help for Gopher client
  110.  INSTALLC   CNTL        How to install the GOPHER MVS client
  111.  INSTALLS   CNTL        How to install the GOPHER MVS server
  112.  LINKC      CNTL        JCL to linkedit the client load module
  113.  LINKS      CNTL        JCL to linkedit the server load modules
  114.  LINKX      CNTL        JCL to linkedit the auxiliary load modules
  115.  MENU       CNTL        Initial Gopher server menu
  116.  PARMS      CNTL        Sample Gopher startup parameters
  117.  SECURE     CNTL        Discussion about making secure REXX scripts
  118.  GOPHER     CLIST       Exec by which users invoke the Gopher client
  119.  NNMFIUCV   CLIST       Exec to check for multiple socket applications
  120.  REXXTEST   CLIST       REXX exec to test the REXX interface with
  121.  TSOHELP    CLIST       Sample REXX exec for Gopher TSO HELP menu hole
  122.  G...       CLIST       REXX exec helpers
  123.  GGM...     PANEL       ISPF regular panels
  124.  ABOUT...   ABOUT       "About This Gopher" text
  125.  GG...      H           C headers      *** SOURCE DISTRIBUTION ONLY ***
  126.  GG...      C           C source       *** SOURCE DISTRIBUTION ONLY ***
  127.  GG...      OBJ         Object modules *** OBJECT DISTRIBUTION ONLY ***
  128.  
  129. --------------------------------------------------------------------
  130.  
  131. Where to Go from Here:
  132.  
  133.  To install the GOPHER MVS client, read member INSTALLC.
  134.  
  135.  To install the GOPHER MVS server, read member INSTALLS.
  136.  
  137. Note:
  138.  
  139.  You may install only the client, only the server, or both the
  140.  client and the server.  It is purely up to what your needs are.
  141.  
  142. --------------------------------------------------------------------
  143.  
  144.  Questions?  Comments?  Suggestions?  Gripes?  Please email to...
  145.  
  146.  Steve Bacher      <seb@draper.com>
  147.  
  148. ./ ADD NAME=$CHANGES
  149. Changes:
  150.  
  151.  November 93 - Version 3 Release 1
  152.  
  153.              Server Enhancements
  154.  
  155.              Support for binary files, including image files, in the
  156.              remote FTP gateway.  Most file types are supported for
  157.              the server, and the client will support some binary types,
  158.              although they cannot be viewed or printed well.
  159.  
  160.              The REXX interface has been completely redesigned.  It is
  161.              not compatible with the previous version, but migration
  162.              should be easy.  Among other things, you can now run REXX
  163.              execs from a non-TSO-environment server, which will allow
  164.              multithreading of client requests that trigger REXX execs.
  165.  
  166.              The access file now supports wildcarding in the file name
  167.              specifications.  Because of this, you must stop and
  168.              restart the gopher server when you change the access file.
  169.              The rules are processed differently.
  170.  
  171.              Additional logging (via write-to-programmer) in a mode
  172.              compatible with the format produced by the U of Minn
  173.              gopher daemon.
  174.  
  175.              Rudimentary support for gopher+ has been added on an
  176.              experimental basis.  Do not rely on this, because it is
  177.              not complete by any means.
  178.  
  179.              Client Enhancements
  180.  
  181.              Printing allows destination in the form nodename.userid.
  182.  
  183.              INITFILE keyword added for a differently named GOPHERRC.
  184.  
  185.  07 Aug 93 - Version 2 Release 2
  186.  
  187.              Remote FTP Gateway
  188.              Enhanced CSO client option
  189.              Configurable GOPHERRC: domain and telnet may be specified
  190.              Object-code-only distribution for those without C compilers
  191.              Improvements to TSO GOPHER exec for users without XPROC
  192.               or without C runtime in linklist
  193.              DD:ddname(member) works now for nested PDS member
  194.               references, making installing the ABOUT PDS simpler
  195.              "E" and "P" work without "S" having to be done first
  196.  
  197.  20 Mar 93 - Version 2 Release 1
  198.  
  199.              Improved browse function
  200.              Printing support
  201.              Bookmark support
  202.              New commands: PRT, INFO, MENU, BOOKMARK
  203.              Configurable startup parameter file
  204.              Ability to run multiple servers on same MVS
  205.  
  206.  07 Dec 92 - Customizations to support SNS/TCPAccess
  207.  
  208.  19 Oct 92 - Improvements in initial startup and GOPHERRC customization
  209.  
  210. ./ ADD NAME=ACCESS
  211. !
  212. ! Format of entries:
  213. !
  214. ! filename (fully qualified, all uppercase, no quotes)
  215. ! can be "DD:DDNAME" or "EXEC:EXECNAME"
  216. !
  217. ! followed by names of hosts which are authorized to access the data.
  218. ! If no host name list is present, all hosts are authorized
  219. !
  220. ! You may specify the same file name more than once, if you need
  221. ! more lines to put host names on.
  222. !
  223. ! Individual PDS members must be specified separately.  A PDS without
  224. ! a member name establishes access only to the PDS directory.
  225. !
  226. ! Note that the default directory MUST be in this table.
  227. !
  228. ! Also note that in the case of EXECs, the EXEC must live in the
  229. ! library allocated to GGEXEC in the Gopher server JCL.
  230. !
  231. ! *** ANY DATA SET REFERENCED BY ANY EXEC IN THAT LIBRARY IS FULLY
  232. ! *** ACCESSIBLE TO GOPHER REGARDLESS OF THIS TABLE!  USE THIS TABLE
  233. ! *** TO GOVERN CONTROL TO THE EXEC ITSELF!!!
  234.  
  235. !
  236. ! below is default directory spec, which MUST be in this table
  237. !
  238. DD:GGGOPHER
  239.  
  240. !
  241. ! Use the following for "About This Gopher".
  242. ! Free free to specify the name of your MVS client host(s)
  243. ! for information pertinent to MVS only.  mvs1 and mvs2 are examples.
  244. !
  245. DD:GGABOUT
  246. DD:GGABOUT(ABOUT)
  247. DD:GGABOUT(ABOUTC)                                mvs1 mvs2
  248. DD:GGABOUT(ABOUTCD)                               mvs1 mvs2
  249. DD:GGABOUT(ABOUTCF)                               mvs1 mvs2
  250. DD:GGABOUT(ABOUTCO)                               mvs1 mvs2
  251. DD:GGABOUT(ABOUTCQ)                               mvs1 mvs2
  252. DD:GGABOUT(ABOUTCS)                               mvs1 mvs2
  253. DD:GGABOUT(ABOUTCSC)                              mvs1 mvs2
  254. DD:GGABOUT(ABOUTCSL)                              mvs1 mvs2
  255. DD:GGABOUT(ABOUTCSM)                              mvs1 mvs2
  256. DD:GGABOUT(ABOUTCSR)                              mvs1 mvs2
  257. DD:GGABOUT(ABOUTCSW)                              mvs1 mvs2
  258. DD:GGABOUT(ABOUTCSX)                              mvs1 mvs2
  259. DD:GGABOUT(ABOUTCX)                               mvs1 mvs2
  260. DD:GGABOUT(ABOUTS)                                mvs1 mvs2
  261. DD:GGABOUT(ABOUTSA)                               mvs1 mvs2
  262. DD:GGABOUT(ABOUTSP)                               mvs1 mvs2
  263. DD:GGABOUT(ABOUTW)
  264. DD:GGABOUT(FAQ)
  265.  
  266. !
  267. ! Here's how to do REXX execs.  Note - no arguments, only exec names
  268. !
  269. EXEC:CHECKLST                     client1 client2 mvs
  270. EXEC:WAISDIR
  271. EXEC:WAISLIST
  272. EXEC:WAISSRCH
  273.  
  274. ANY.PUBLIC.SEQ.DS
  275. ANY.SEMI.PUBLIC.SEQ.DS            goodclient1 goodclient2
  276. ANY.SEMI.PUBLIC.SEQ.DS            goodclient3 goodclient4
  277.  
  278. ! PDS without member name provides access to directory only
  279. ! All member names must be explicitly listed to be accessible.
  280.  
  281. ANY.PUBLIC.PDS
  282. ANY.PUBLIC.PDS(MEMBER1)
  283. ANY.PUBLIC.PDS(MEMBER2)
  284. ANY.PUBLIC.PDS(MEMBER3)
  285. ANY.PUBLIC.PDS(MEMBER4)
  286.  
  287.  
  288. ANY.SEMI.PUBLIC.PDS               goodclient1 goodclient2
  289. ANY.SEMI.PUBLIC.PDS               goodclient3 goodclient4
  290. ANY.SEMI.PUBLIC.PDS(MEMBER1)      goodclient1
  291. ANY.SEMI.PUBLIC.PDS(MEMBER2)      goodclient2
  292. ANY.SEMI.PUBLIC.PDS(MEMBER3)      goodclient3
  293. ANY.SEMI.PUBLIC.PDS(MEMBER4)      goodclient4
  294.  
  295. ./ ADD NAME=ALLOAD
  296. //JOBNAME  JOB ACCOUNT,'NAME'
  297. //*                                                                  */
  298. //* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  299. //*                                                                  */
  300. //* This software is provided on an "AS IS" basis.  All warranties,  */
  301. //* including the implied warranties of merchantability and fitness, */
  302. //* are expressly denied.                                            */
  303. //*                                                                  */
  304. //* Provided this copyright notice is included, this software may    */
  305. //* be freely distributed and not offered for sale.                  */
  306. //*                                                                  */
  307. //* Changes or modifications may be made and used only by the maker  */
  308. //* of same, and not further distributed.  Such modifications should */
  309. //* be mailed to the author for consideration for addition to the    */
  310. //* software and incorporation in subsequent releases.               */
  311. //*                                                                  */
  312. //*
  313. //* Allocate GOPHER load and object libraries before install
  314. //*
  315. //GGALLOC PROC U='3380',V=''
  316. //*
  317. //IEFBR14  EXEC PGM=IEFBR14
  318. //ALLOCDD  DD   DISP=(NEW,CATLG,DELETE),DSN=&LIB,
  319. //         DCB=(RECFM=&RF,LRECL=&LR,BLKSIZE=&BS),
  320. //         SPACE=(&BS,(&PRI,&SEC,&DIR)),UNIT=&U,VOL=SER=&V
  321. //*
  322. //         PEND
  323. //*
  324. //* The ALLOCL step allocates the load library from which the
  325. //* executable program will be run.  If you intend to place the
  326. //* executable into an existing library, you can skip this step.
  327. //* Otherwise, the name must match the name used on the LOADLIB
  328. //* parameter of the GGLINK procedure in the LINK* JCL steps.
  329. //*
  330. //* If you want separate libraries for the client and the server,
  331. //* just duplicate this step and give the LIB's different names.
  332. //*
  333. //* The ALLOCO step allocates the object library into which the
  334. //* source modules will be compiled.  This library is required
  335. //* for the compile and link steps, but is not required for run
  336. //* time execution.  However, you may wish to keep the object
  337. //* library around in case there are fixes for which you will be
  338. //* recompiling individual Gopher source modules.
  339. //*
  340. //ALLOCL   EXEC GGALLOC,PRI=50,SEC=50,DIR=35,RF=U,LR=,BS=6233,
  341. //         LIB='GOPHER.LOAD'
  342. //ALLOCO   EXEC GGALLOC,PRI=50,SEC=50,DIR=35,RF=FB,LR=80,BS=2960,
  343. //         LIB='GOPHER.INSTALL.OBJ'
  344. //*
  345. ./ ADD NAME=COMPILE
  346. //JOBNAME  JOB ACCOUNT,'NAME'
  347. //*                                                                  */
  348. //* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  349. //*                                                                  */
  350. //* This software is provided on an "AS IS" basis.  All warranties,  */
  351. //* including the implied warranties of merchantability and fitness, */
  352. //* are expressly denied.                                            */
  353. //*                                                                  */
  354. //* Provided this copyright notice is included, this software may    */
  355. //* be freely distributed and not offered for sale.                  */
  356. //*                                                                  */
  357. //* Changes or modifications may be made and used only by the maker  */
  358. //* of same, and not further distributed.  Such modifications should */
  359. //* be mailed to the author for consideration for addition to the    */
  360. //* software and incorporation in subsequent releases.               */
  361. //*                                                                  */
  362. //*********************************************************************
  363. //*
  364. //* Compile some or all GOPHER C/370 sources to make the SYSLIN input
  365. //* to the linkedit of the executable Gopher load module(s).
  366. //*
  367. //GGCC   PROC MEMBER=,
  368. //            SRCLIB='GOPHER.INSTALL.C',         GOPHER C source PDS
  369. //            HDRLIB='GOPHER.INSTALL.H',         GOPHER C headers PDS
  370. //            OBJLIB='GOPHER.INSTALL.OBJ',       GOPHER object library
  371. //            COMMHDR='TCPIP.COMMMAC',           C/370 TCP/IP headers
  372. //            C370HDR='SYS1.EDCHDRS',            C/370 standard headers
  373. //            SYSMSGS='SYS1.EDCMSGS',            C/370 messages file
  374. //            SYSMSGM='EDCMSGE',                 C/370 message member
  375. //            VIOUNIT=VIO,                       Temporary disk unit
  376. //            OUTCLAS='*',                          SYSOUT class
  377. //            CPARMS='SOURCE EXPMAC NOAGGR NOXREF', Compile parameters
  378. //            TEST=TEST                             TEST or NOTEST
  379. //*
  380. //CCOMP     EXEC PGM=EDCCOMP,PARM='MARGINS(1,72) &TEST &CPARMS'
  381. //SYSMSGS   DD DISP=SHR,DSN=&SYSMSGS(&SYSMSGM)
  382. //SYSIN     DD DISP=SHR,DSN=&SRCLIB(&MEMBER)
  383. //SYSLIN    DD DISP=OLD,DSN=&OBJLIB(&MEMBER)
  384. //SYSLIB    DD DISP=SHR,DSN=&COMMHDR
  385. //          DD DISP=SHR,DSN=&C370HDR
  386. //USERLIB   DD DISP=SHR,DSN=&HDRLIB
  387. //SYSPRINT  DD SYSOUT=&OUTCLAS
  388. //SYSCPRT   DD SYSOUT=&OUTCLAS
  389. //SYSUT1    DD DSN=&&SYSUT1,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
  390. //   SPACE=(32000,(30,30)),DCB=(RECFM=FB,LRECL=80,BLKSIZE=3200)
  391. //SYSUT4    DD DSN=&&SYSUT4,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
  392. //   SPACE=(32000,(30,30)),DCB=(RECFM=FB,LRECL=80,BLKSIZE=3200)
  393. //SYSUT6    DD DSN=&&SYSUT6,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
  394. //   SPACE=(32000,(30,30)),DCB=(RECFM=FB,LRECL=3200,BLKSIZE=12800)
  395. //SYSUT7    DD DSN=&&SYSUT7,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
  396. //   SPACE=(32000,(30,30)),DCB=(RECFM=FB,LRECL=3200,BLKSIZE=12800)
  397. //SYSUT8    DD DSN=&&SYSUT8,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
  398. //   SPACE=(32000,(30,30)),DCB=(RECFM=FB,LRECL=3200,BLKSIZE=12800)
  399. //SYSUT9    DD DSN=&&SYSUT9,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
  400. //   SPACE=(32000,(30,30)),DCB=(RECFM=VB,LRECL=137,BLKSIZE=882)
  401. //SYSUT10   DD SYSOUT=&OUTCLAS
  402. //*
  403. //         PEND
  404. //*
  405. //GGACCES  EXEC GGCC,MEMBER=GGACCES
  406. //GGALLOC  EXEC GGCC,MEMBER=GGALLOC
  407. //GGASVC   EXEC GGCC,MEMBER=GGASVC
  408. //GGBARF   EXEC GGCC,MEMBER=GGBARF
  409. //GGBIN    EXEC GGCC,MEMBER=GGBIN
  410. //GGBKMGR  EXEC GGCC,MEMBER=GGBKMGR
  411. //GGCLIEN  EXEC GGCC,MEMBER=GGCLIEN
  412. //GGCLRTX  EXEC GGCC,MEMBER=GGCLRTX
  413. //GGCONN   EXEC GGCC,MEMBER=GGCONN
  414. //GGCSO    EXEC GGCC,MEMBER=GGCSO
  415. //GGDBM    EXEC GGCC,MEMBER=GGDBM
  416. //GGDFAIL  EXEC GGCC,MEMBER=GGDFAIL
  417. //GGDIR    EXEC GGCC,MEMBER=GGDIR
  418. //GGDISC   EXEC GGCC,MEMBER=GGDISC
  419. //GGDISPL  EXEC GGCC,MEMBER=GGDISPL
  420. //GGDSOPT  EXEC GGCC,MEMBER=GGDSOPT
  421. //GGDUMP   EXEC GGCC,MEMBER=GGDUMP
  422. //GGESRVR  EXEC GGCC,MEMBER=GGESRVR
  423. //GGFREEM  EXEC GGCC,MEMBER=GGFREEM
  424. //GGFTP    EXEC GGCC,MEMBER=GGFTP
  425. //GGGETDS  EXEC GGCC,MEMBER=GGGETDS
  426. //GGGETM   EXEC GGCC,MEMBER=GGGETM
  427. //GGGOFOR  EXEC GGCC,MEMBER=GGGOFOR
  428. //GGGSRVL  EXEC GGCC,MEMBER=GGGSRVL
  429. //GGIERR   EXEC GGCC,MEMBER=GGIERR
  430. //GGIGET   EXEC GGCC,MEMBER=GGIGET
  431. //GGINFO   EXEC GGCC,MEMBER=GGINFO
  432. //GGISPF   EXEC GGCC,MEMBER=GGISPF
  433. //GGIVGET  EXEC GGCC,MEMBER=GGIVGET
  434. //GGIVPUT  EXEC GGCC,MEMBER=GGIVPUT
  435. //GGMENU   EXEC GGCC,MEMBER=GGMENU
  436. //GGMTFER  EXEC GGCC,MEMBER=GGMTFER
  437. //GGOUTS   EXEC GGCC,MEMBER=GGOUTS
  438. //GGOUTTX  EXEC GGCC,MEMBER=GGOUTTX
  439. //GGPMSG   EXEC GGCC,MEMBER=GGPMSG
  440. //GGPROC   EXEC GGCC,MEMBER=GGPROC
  441. //GGREXX   EXEC GGCC,MEMBER=GGREXX
  442. //GGSERVE  EXEC GGCC,MEMBER=GGSERVE
  443. //GGSLEEP  EXEC GGCC,MEMBER=GGSLEEP
  444. //GGSOCKT  EXEC GGCC,MEMBER=GGSOCKT
  445. //GGSOPT   EXEC GGCC,MEMBER=GGSOPT
  446. //GGSTASK  EXEC GGCC,MEMBER=GGSTASK
  447. //GGTEMP   EXEC GGCC,MEMBER=GGTEMP
  448. //GGTNET   EXEC GGCC,MEMBER=GGTNET
  449. //GGTSO    EXEC GGCC,MEMBER=GGTSO
  450. //GGTYPE   EXEC GGCC,MEMBER=GGTYPE
  451. //GGUNALC  EXEC GGCC,MEMBER=GGUNALC
  452. //GGVIEW   EXEC GGCC,MEMBER=GGVIEW
  453. //GGVTX    EXEC GGCC,MEMBER=GGVTX
  454. //GGWAIS   EXEC GGCC,MEMBER=GGWAIS
  455. //GGWHOIS  EXEC GGCC,MEMBER=GGWHOIS
  456. //GGWTO    EXEC GGCC,MEMBER=GGWTO
  457. //GGXTX    EXEC GGCC,MEMBER=GGXTX
  458. //XGALLOC  EXEC GGCC,MEMBER=XGALLOC
  459. //XGSLEEP  EXEC GGCC,MEMBER=XGSLEEP
  460. //XGWTO    EXEC GGCC,MEMBER=XGWTO
  461. //*
  462. ./ ADD NAME=GOPHERD
  463. //GOPHERD  PROC MODULE=GGSERVER,
  464. //         STEPLIB='GOPHER.LOAD',
  465. //         EXECLIB='GOPHER.EXEC',
  466. //         ACCESS='GOPHER.ACCESS',
  467. //         ABOUT='GOPHER.ABOUT',
  468. //         MENU='GOPHER.MENU',
  469. //         PARMS='GOPHER.PARMS',
  470. //         VIO=SYSVIO,
  471. //         STDERR='*',
  472. //         STDOUT='*',
  473. //         GPARM=
  474. //*
  475. //*********************************************************************
  476. //*                                                                   *
  477. //* GOPHER daemon, by Shawn Hart (U.Del.) and Steve Bacher (D.Lab.)   *
  478. //*                                                                   *
  479. //* Straight batch (no TSO access)                                    *
  480. //*                                                                   *
  481. //*********************************************************************
  482. //*
  483. //GOPHERD  EXEC PGM=&MODULE,PARM='&GPARM'
  484. //STEPLIB  DD   DISP=SHR,DSN=&STEPLIB
  485. //GGEXEC   DD   DISP=SHR,DSN=&EXECLIB
  486. //SYSTSPRT DD   UNIT=&VIO,SPACE=(TRK,(100,100)),RECFM=VBA,LRECL=255
  487. //SYSERR   DD   SYSOUT=&STDERR
  488. //SYSPRINT DD   SYSOUT=&STDOUT
  489. //SYSTSIN  DD   DUMMY
  490. //SYSIN    DD   DUMMY
  491. //GGDEBUG  DD   SYSOUT=*
  492. //GGABOUT  DD   DISP=SHR,DSN=&ABOUT
  493. //GGACCESS DD   DISP=SHR,DSN=&ACCESS
  494. //GGGOPHER DD   DISP=SHR,DSN=&MENU
  495. //GGPARMS  DD   DISP=SHR,DSN=&PARMS
  496. ./ ADD NAME=GOPHERT
  497. //GOPHERD  PROC MODULE=GGSERVER,
  498. //         STEPLIB='GOPHER.LOAD',
  499. //         EXECLIB='GOPHER.EXEC',
  500. //         ACCESS='GOPHER.ACCESS',
  501. //         ABOUT='GOPHER.ABOUT',
  502. //         MENU='GOPHER.MENU',
  503. //         PARMS='GOPHER.PARMS',
  504. //         VIO=SYSVIO,
  505. //         STDERR='*',
  506. //         STDOUT='*',
  507. //         GPARM=
  508. //*
  509. //*********************************************************************
  510. //*                                                                   *
  511. //* GOPHER daemon, by Shawn Hart (U.Del.) and Steve Bacher (D.Lab.)   *
  512. //*                                                                   *
  513. //* Batch with TSO environment - required only to run REXX execs      *
  514. //* that use TSO services                                             *
  515. //*                                                                   *
  516. //*********************************************************************
  517. //*
  518. //GOPHERD  EXEC PGM=IKJEFT01,DYNAMNBR=128,REGION=8M,
  519. //         PARM='&MODULE &GPARM'
  520. //STEPLIB  DD   DISP=SHR,DSN=&STEPLIB
  521. //GGEXEC   DD   DISP=SHR,DSN=&EXECLIB
  522. //SYSTSPRT DD   UNIT=&VIO,SPACE=(TRK,(100,100)),RECFM=VBA,LRECL=255
  523. //SYSERR   DD   SYSOUT=&STDERR
  524. //SYSPRINT DD   SYSOUT=&STDOUT
  525. //SYSTSIN  DD   DUMMY
  526. //SYSIN    DD   DUMMY
  527. //GGDEBUG  DD   SYSOUT=*
  528. //GGABOUT  DD   DISP=SHR,DSN=&ABOUT
  529. //GGACCESS DD   DISP=SHR,DSN=&ACCESS
  530. //GGGOPHER DD   DISP=SHR,DSN=&MENU
  531. //GGPARMS  DD   DISP=SHR,DSN=&PARMS
  532. ./ ADD NAME=HELP
  533. )F Function -
  534.  
  535.  GOPHER is a distributed document delivery service, or, more generally,
  536.  a networked information retrieval service.  It allows you to access
  537.  numerous types of data on various hosts in a transparent fashion.
  538.  GOPHER presents you with a hierarchical display of information sources
  539.  which are accessed via a client/server communications link.
  540.  
  541.  There are GOPHER clients for all common hardware platforms.  The MVS
  542.  version runs as an ISPF dialog application.
  543.  
  544.  When you use the GOPHER client, information about your use of GOPHER
  545.  is stored in a data set called GOPHERRC.  If you don't have one,
  546.  GOPHER will create it for you.  You can specify a different name
  547.  for this data set with the INITFILE keyword.
  548.  
  549.  You can save Gopher information in bookmark files.  See the
  550.  help for operand BOOKMARK for details.
  551.  
  552.  For more information on customizing your GOPHER environment, get
  553.  into Gopher and select "About This GOPHER".
  554.  
  555. )I GOPHLOC          - local GOPHER help goes in member GOPHLOC
  556.  
  557. )X Syntax -
  558.  
  559.    %GOPHER
  560.               LOCAL
  561.               BOOKMARK(datasetname)
  562.               INITFILE(gopherrcname)
  563.               SERVER(hostname)
  564.               PATH(pathname)
  565.               PORT(portnumber)
  566.               DESCRIPTION(text)
  567.               FORCE
  568.               DEBUG
  569.               TEST
  570.  
  571.    Required:  none
  572.  
  573.    Defaults:  INITFILE defaults to tsouserid.GOPHERRC
  574.  
  575. )O Operands -
  576.  
  577. ))LOCAL
  578.  
  579.               Specify LOCAL if you want to enter GOPHER in "serverless"
  580.               mode - i.e. start up with your private GOPHER menu.
  581.               Specifying LOCAL accomplishes two things:
  582.  
  583.                (1) It sets the server to "-", meaning local access.
  584.                    Therefore, you must also provide a path, either
  585.                    via the PATH operand or via a "localmenu:" spec
  586.                    in your GOPHERRC file.
  587.  
  588.                (2) It allows you to use GOPHER even if there are
  589.                    other TCP/IP socket applications active elsewhere
  590.                    in your TSO session.  However, it will not allow
  591.                    you to connect to any GOPHER servers, even if you
  592.                    have a local menu item that points to one.
  593.  
  594.               For information on how to set up GOPHER menus, get into
  595.               GOPHER and select "About This Gopher".
  596.  
  597. ))BOOKMARK(datasetname)
  598.  
  599.               The name of a data set containing Gopher bookmarks,
  600.               using normal TSO data set naming conventions.
  601.  
  602.               You can create bookmarks in GOPHER by using the "B"
  603.               selection code next to a menu item, or by using the
  604.               BOOKMARK command while browsing an entry.  GOPHER will
  605.               append an entry for the selected item to the end of
  606.               the data set that you specify when asked.
  607.  
  608.               To access this bookmark in a Gopher session, you can use
  609.               the MENU command from any Gopher menu display, or you can
  610.               start Gopher with a specific bookmark file.
  611.  
  612. ))INITFILE(gopherrcname)
  613.  
  614.               The name of a data set containing startup information,
  615.               commonly referred to as your "GOPHERRC" file.  If this
  616.               file does not exist, it will be automatically created.
  617.               The default for this name is tsouserid.GOPHERRC.
  618.  
  619. ))SERVER(hostname)
  620.  
  621.               The host name (or IP address) of a Gopher server.
  622.               If this is not given, GOPHER looks in your GOPHERRC
  623.               to find what server to connect to.  If it can't find
  624.               an appropriate specification, you will have to enter
  625.               a server name on the startup panel.
  626.  
  627.               A server name of a single minus sign (-) is a special
  628.               case, signifying local (serverless) access to your
  629.               own private GOPHER data.  In this case, you must tell
  630.               GOPHER where your menu is, either via the PATH operand
  631.               or in the GOPHERRC file.
  632.  
  633. ))PATH(pathname)
  634.  
  635.               The path name to be passed to the Gopher server, or
  636.               used in local access as your initial menu.  Although
  637.               the exact interpretation of the pathname string varies
  638.               depending on the server, both the MVS server and the
  639.               local GOPHER access feature interpret the pathname
  640.               as the FULLY QUALIFIED WITHOUT QUOTES name of an MVS
  641.               data set containing a gopher menu.  For information
  642.               about the format of a gopher menu, see operand MENU.
  643.  
  644. ))PORT(portnumber)
  645.  
  646.               You should never need to specify this field unless
  647.               someone has set up a special kind of Gopher server that
  648.               requires a unique port number.  In such a case, you
  649.               would generally use this along with the SERVER operand.
  650.  
  651. ))DESCRIPTION(text)
  652.  
  653.               A text string giving the heading to be displayed for
  654.               the initial directory of Gopher goodies.  Normally
  655.               either the Gopher server or the Gopher client will
  656.               have a default value for this, or you can specify
  657.               a description of your liking in your GOPHERRC file.
  658.               You can also use this to override the description
  659.               generated when you use the BOOKMARK operand to start up.
  660.  
  661. ))FORCE
  662.  
  663.               GOPHER tries to determine if there is a TCP/IP socket
  664.               application active elsewhere in your TSO environment
  665.               before starting up, to prevent TCP/IP errors.  If it
  666.               tells you that there is another client active but in
  667.               truth there is none and you know it, you can use the
  668.               FORCE keyword to make GOPHER proceed whether it finds
  669.               this to be the case or not.
  670.  
  671.               Using the LOCAL operand is one way to avoid this entire
  672.               scenario.  However, that won't allow you to access any
  673.               Gopher servers on the network.
  674.  
  675. ))DEBUG
  676.  
  677.               Set debugging mode on.  You must preallocate a file to
  678.               ddname GGDEBUG for this to work.  This can be allocated
  679.               to the terminal or a log file.  When debug mode is on,
  680.               messages describing memory allocation and deallocation
  681.               and GOPHER queries sent are dumped to the debug file.
  682.  
  683. ))TEST
  684.  
  685.               Activate C/370 interactive test (INSPECT).  GOPHER must
  686.               have been compiled with the TEST option for this to be
  687.               effective.  Note that you can also issue the TEST command
  688.               inside GOPHER to get to INSPECT, again provided that
  689.               GOPHER was compiled with the TEST option.
  690.  
  691. ./ ADD NAME=INSTALLC
  692.  
  693.  Directions for Installing the GOPHER MVS Client
  694.  
  695.  where @ is the install prefix from the unload and $ is a system prefix
  696.  
  697.  Summary:
  698.  
  699.  1. (all users)      Customize @.H      - GGUSER
  700.  2. (all users)      Customize @.CNTL   - ALLOAD
  701.  3. (all users)      Customize @.CNTL   - COMPILE
  702.  4. (all users)      Customize @.CNTL   - LINKC
  703.  5. (all users)      Customize @.CLIST  - GOPHER
  704.  6. (if not ISPF V3) Edit      @.PANEL  - GGMP*
  705.  7. (all users)      Submit    @.CNTL   - ALLOAD   ==> $.LOAD, @.OBJ
  706.  8. (all users)      Submit    @.CNTL   - COMPILE  --> @.OBJ(*)
  707.  9. (all users)      Submit    @.CNTL   - LINKC    --> $.LOAD(GG*)
  708.  10.(REXX users)     Submit    @.CNTL   - LINKX    --> $.LOAD(XG*)
  709.  11.(all users)      Install   @.CNTL   - HELP     --> $.HELP(GOPHER)
  710.  12.(all users)      Install   @.CLIST  - GOPHER   --> $.CLIST(GOPHER)
  711.  13.(all users)      Install   @.CLIST  - NNMFIUCV --> $.CLIST(NNMFIUCV)
  712.  14.(REXX users)     Install   @.CLIST  - *        --> $.CLIST(*)
  713.  15.(all users)      Install   @.PANEL  - *        --> $.PANEL(*)
  714.  16.(all users)      Install   @.ABOUT  - *        --> $.ABOUT(*)
  715.  
  716.  System libraries to be updated:
  717.  
  718.  $.LOAD  - specified in .CNTL(ALLOAD)
  719.  $.OBJ   - specified in .CNTL(ALLOAD)
  720.  $.HELP  - your existing logon-time TSO HELP  (SYSHELP) library
  721.  $.CLIST - your existing logon-time TSO CLIST (SYSPROC) library
  722.  $.PANEL - your existing logon-time ISPF PANEL (ISPPLIB) library
  723.  $.ABOUT - a new PDS you make yourself, or use the install copy
  724.  
  725.  Assuming you have unloaded all the install PDS's:
  726.  
  727.  1. Customize the GGUSER header file as shown by the comments therein.
  728.  Note in particular the defines for your TCP/IP and your C compiler.
  729.  There are changes to the linkedit JCL that are related to these.
  730.  
  731.  2,3,4. Customize the ALLOAD, COMPILE and LINKC JCL members to reflect
  732.  your local conventions.  Note:  If you intend to place the executable
  733.  into an existing library, you can suppress that part of the ALLOAD JCL.
  734.  The name of the data set created must match across both members.
  735.  
  736.  *********************************************************************
  737.  
  738.  IMPORTANT:  If you are running TCP/IP V2R2 or higher on MVS, you must
  739.  change the following library names in the compile and link JCL:
  740.  
  741.    TCPIP.COMMMAC   should be changed to  TCPIP.SEZACMAC
  742.    TCPIP.COMMTXT   should be changed to  TCPIP.SEZACMTX
  743.  
  744.  If you are using SNS/TCPAccess, use these library names, or
  745.  whatever names are defined at your installation:
  746.  
  747.    TCPIP.COMMMAC   should be changed to  SNSTCP.V110.H
  748.    TCPIP.COMMTXT   should be changed to  SNSTCP.V110.CILIB
  749.  
  750.  If you are using SAS/C, change CEESTART to MAIN in the linkedit
  751.  ENTRY control statement.
  752.  
  753.  *********************************************************************
  754.  
  755.  Note:  If you have defined C370V1 in the GGUSER header file, you must
  756.  also include the system linklist load library or libraries containing
  757.  ISPLINK, ISPEXEC and IKJEFF18 when linking.  Otherwise you may delete
  758.  the lines from the linkedit JCL that reference them.
  759.  
  760.  Note:  You need not include the PASCAL libraries or the AMPZMVSB
  761.  module if you are using TCP/IP Version 2 or higher, in which case
  762.  you must also define TCPIPV2 in the GGUSER headerfile.
  763.  
  764.  5. Customize the GOPHER exec to define the names of the MVS libraries
  765.  to contain the panel and load library members.  The load library must
  766.  be the one specified in the ALLOAD JCL, if you are creating it anew.
  767.  Observe the comments relating to the use of LIBDEF and ISPF APPLIDs.
  768.  
  769.  It is in the GOPHER exec that you will also customize the name of the
  770.  default Gopher server.  Note that the user's GOPHERRC file gets built
  771.  from the contents of this exec.
  772.  
  773.  You may configure the GOPHER exec to use XPROC to parse the operands
  774.  given to it by the TSO user.  If you don't have XPROC, you should get
  775.  it, because the user can take advantage of all the power of TSO CLIST
  776.  style parsing if you do.  The GOPHER exec contains some code that
  777.  emulates full TSO parsing, but it isn't as robust or flexible as true
  778.  XPROC parsing.  You can get XPROC from ftp.mic.ucla.edu in directory
  779.  /pub/mvs/util, as part of the TSOREXX distribution.
  780.  
  781.  If the C/370 runtime library is not in the link list or otherwise
  782.  available to ISPF at execution time, you may arrange for it to be
  783.  allocated via LIBDEF in the GOPHER exec by setting "crunlibs".
  784.  
  785.  6. If you are running ISPF Version 2 or earlier, edit the GOPHER panels
  786.  whose names begin "GGMP...".  These are popups, and will not work
  787.  under ISPF Version 2 unless you change the )BODY line.  Remove the
  788.  WINDOW(...) parameter from the )BODY line of each panel so that the
  789.  line just says )BODY or )BODY EXPAND(``), as the case may be.
  790.  
  791.  7. Submit the ALLOAD JCL to allocate the load library from which the
  792.  executable program will be run, as well as the object library in which
  793.  the compiled object modules will be stored.
  794.  
  795.  8. Submit the COMPILE JCL to compile all the C sources and create the
  796.  required object modules in the object library built in the above step.
  797.  Note that this compiles all the modules for both the client and the
  798.  server.  If you are installing both, you need not repeat this step.
  799.  
  800.  9. Submit the LINKC JCL to create the executable Gopher load module
  801.  from the object modules created in the above step.  This will create
  802.  or replace the load module GGCLIENT.
  803.  
  804.  Note:  The linkedit must complete with a return code of zero.  If not,
  805.  don't use the resultant load module.  Check the libraries you specified
  806.  on the link step to see what went wrong.
  807.  
  808.  In the future, if you have to recompile individual modules, you can use
  809.  the same JCL to compile only those modules, and the link will include
  810.  the new modules in the existing executable load module.  To do this,
  811.  you must retain the object library built above.
  812.  
  813.  10. Submit the LINKX JCL to create the auxiliary Gopher load modules
  814.  from the object modules created in the above step.  This will create
  815.  or replace load modules named XG..., used by the REXX interface.
  816.  
  817.  11. Copy the help member (HELP) from the CNTL PDS into your local TSO
  818.  HELP library under the name GOPHER.  You may also create an additional
  819.  HELP member called GOPHLOC containing information local to your site,
  820.  if you wish.
  821.  
  822.  12. Copy the GOPHER exec from the CLIST PDS into your local TSO CLIST
  823.  library under the name GOPHER.  You may install it in a REXX exec
  824.  library allocated to SYSEXEC if that is your convention for REXX execs
  825.  as opposed to CLISTs.
  826.  
  827.  13. If you install the GOPHER exec, you must also install
  828.  the NNMFIUCV exec in the same library.  This exec implements a rude
  829.  check for an existing TCP/IP socket application (e.g. another GOPHER)
  830.  in a different PIE MultiTSO session.  It prevents your users from
  831.  crashing TCP/IP, so it is highly recommended that you make use of it.
  832.  
  833.  14. Install the remainder of the execs in a library that will be
  834.  accessible to the client in local mode (possibly the same library).
  835.  These execs are required by the new REXX interface.
  836.  
  837.  15. Copy all the members of the panel PDS into the ISPF panel library
  838.  specified in the GOPHER exec.
  839.  
  840.  16. Create the "About This Gopher" PDS from the ABOUT PDS.  This has
  841.  all the text users should see when they select the "About This Gopher"
  842.  item from the MVS client.  It also contains all the documentation you
  843.  need about setting up the client and the server, as well as creating
  844.  menus and REXX execs for use with MVS Gopher.  You may have already
  845.  done this as part of the server install, but it should also be
  846.  available from the client in "local" (serverless) mode, so that is
  847.  why I mention it here.
  848.  
  849. --------------------------------------------------------------------
  850.  
  851.  Note:  Make sure that the C/370 run time library is available,
  852.  either in the system link list or in the ISPLLIB concatenation,
  853.  before attempting to run GOPHER.  See above under customization
  854.  of the GOPHER exec.
  855.  
  856. ./ ADD NAME=INSTALLS
  857.  
  858.  Directions for Installing the GOPHER MVS Server
  859.  
  860.  where @ is the install prefix from the unload and $ is a system prefix
  861.  
  862.  Summary:
  863.  
  864.  1. (all users)      Customize @.H      - GGUSER
  865.  2. (all users)      Customize @.CNTL   - ALLOAD
  866.  3. (all users)      Customize @.CNTL   - COMPILE
  867.  4. (all users)      Customize @.CNTL   - LINKC
  868.  5. (all users)      Submit    @.CNTL   - ALLOAD   ==> $.LOAD, @.OBJ
  869.  6. (all users)      Submit    @.CNTL   - COMPILE  --> @.OBJ(*)
  870.  7. (all users)      Submit    @.CNTL   - LINKC    --> $.LOAD(GG*)
  871.  8. (REXX users)     Submit    @.CNTL   - LINKX    --> $.LOAD(XG*)
  872.  9. (all users)      Install   @.ABOUT  - *        --> $.ABOUT(*)
  873.  10.(all users)      Create    access file         ... DD:GGACCESS
  874.  11.(all users)      Create    startup parameters  ... DD:GGPARMS
  875.  12.(REXX users)     Create    REXX exec PDS       ... DD:GGEXEC
  876.  13.(REXX users)     Install   @.CLIST  - *        --> $.CLIST(*)
  877.  14.(all users)      Create    started task JCL    --> SYS1.PROCLIB
  878.  15.(all users)      Update    TCP/IP profile      --> TCPIP.TCPIP.PROFI
  879.  
  880.  System libraries to be updated:
  881.  
  882.  $.LOAD  - specified in .CNTL(ALLOAD)
  883.  $.OBJ   - specified in .CNTL(ALLOAD)
  884.  $.ABOUT - a new PDS you make yourself, or use the install copy
  885.  
  886.  Assuming you have unloaded all the install PDS's:
  887.  
  888.  1. Customize the GGUSER header file as shown by the comments therein.
  889.  Note in particular the defines for your TCP/IP and your C compiler.
  890.  There are changes to the linkedit JCL that are related to these.
  891.  
  892.  2,3,4. Customize the ALLOAD, COMPILE and LINKS JCL members to reflect
  893.  your local conventions.  Note:  If you intend to place the executable
  894.  into an existing library, you can suppress that part of the ALLOAD JCL.
  895.  The name of the data set created must match across both members.
  896.  
  897.  *********************************************************************
  898.  
  899.  IMPORTANT:  If you are running TCP/IP V2R2 or higher on MVS, you must
  900.  change the following library names in the compile and link JCL:
  901.  
  902.    TCPIP.COMMMAC   should be changed to  TCPIP.SEZACMAC
  903.    TCPIP.COMMTXT   should be changed to  TCPIP.SEZACMTX
  904.  
  905.  If you are using SNS/TCPAccess, use these library names, or
  906.  whatever names are defined at your installation:
  907.  
  908.    TCPIP.COMMMAC   should be changed to  SNSTCP.V110.H
  909.    TCPIP.COMMTXT   should be changed to  SNSTCP.V110.CILIB
  910.  
  911.  If you are using SAS/C, change CEESTART to MAIN in the linkedit
  912.  ENTRY control statement.
  913.  
  914.  *********************************************************************
  915.  
  916.  Note:  If you have defined C370V1 in the GGUSER header file, you must
  917.  also include the system linklist load library containing IKJEFF18
  918.  when linking.  Otherwise you may delete the line from the linkedit
  919.  JCL that references it.
  920.  
  921.  Note:  You need not include the PASCAL libraries or the AMPZMVSB
  922.  module if you are using TCP/IP Version 2 or higher, in which case
  923.  you must also define TCPIPV2 in the GGUSER headerfile.
  924.  
  925.  5. Submit the ALLOAD JCL to allocate the load library from which the
  926.  executable program will be run, as well as the object library in which
  927.  the compiled object modules will be stored.
  928.  
  929.  6. Submit the COMPILE JCL to compile all the C sources and create the
  930.  required object modules in the object library built in the above step.
  931.  Note that this compiles all the modules for both the client and the
  932.  server.  If you are installing both, you need not repeat this step.
  933.  
  934.  7. Submit the LINKS JCL to create the executable Gopher load modules
  935.  from the object modules created in the above step.  This will create
  936.  or replace the load modules GGSERVER and GGSTASK.
  937.  
  938.  Note:  The linkedit must complete with a return code of zero.  If not,
  939.  don't use the resultant load module.  Check the libraries you specified
  940.  on the link step to see what went wrong.
  941.  
  942.  In the future, if you have to recompile individual modules, you can use
  943.  the same JCL to compile only those modules, and the link will include
  944.  the new modules in the existing executable load module.  To do this,
  945.  you must retain the object library built above.
  946.  
  947.  8. Submit the LINKX JCL to create the auxiliary Gopher load modules
  948.  from the object modules created in the above step.  This will create
  949.  or replace load modules named XG..., used by the REXX interface.
  950.  
  951.  9. Create the "About This Gopher" PDS from the ABOUT PDS.  This has
  952.  all the text users should see when they select the "About This Gopher"
  953.  item from the MVS client.  It also contains all the documentation you
  954.  need about setting up the client and the server, as well as creating
  955.  menus and REXX execs for use with MVS Gopher.  You may have already
  956.  done this as part of the client install.
  957.  
  958.  Note that member MENU contains the line PATH=DD:GGABOUT(ABOUT).  This
  959.  works now (it didn't use to), so there is no need to change it as long
  960.  as you have the GGABOUT DD statement in your server JCL pointing to
  961.  your ABOUT PDS (see below).
  962.  
  963.  10. Create your Gopher access file.  See the instructions in the
  964.  "About This Gopher" PDS, member ABOUTSA, for a description of the
  965.  format.  A sample member is in member ACCESS of this CNTL PDS.
  966.  
  967.  11. Create your Gopher startup parameter file.  This is not required,
  968.  but may be used to change compiled-in defaults.  See the PARMS member
  969.  for a default.
  970.  
  971.  12. Allocate a PDS to hold Gopher REXX execs.  This is required only
  972.  if you plan to use the REXX interface for driver scripts.  See the
  973.  TSOHELP exec in the CLIST PDS of the distribution for a sample
  974.  application.
  975.  
  976.  13. Install all of the execs in the CLIST PDS in the library created
  977.  above.  These execs, with the exception of GOPHER and NNMFIUCV,
  978.  are required by the new REXX interface.
  979.  
  980.  14. Create the MVS Gopher started task JCL from either of the samples
  981.  given in GOPHERD and GOPHERT.  The GOPHERT is recommended so that you
  982.  can use REXX execs that issue TSO commands, but you may not want to
  983.  use this for security reasons.  Either way, customize liberally.
  984.  
  985.  Started task parameters:
  986.  
  987.  MODULE=GGSERVER            the Gopher server load module in STEPLIB
  988.  STEPLIB='GOPHER.LOAD'      the load library containing the above
  989.  EXECLIB='GOPHER.EXEC'      the PDS containing server REXX execs
  990.  ACCESS='GOPHER.ACCESS'     the installation access file (sequential)
  991.  ABOUT='GOPHER.ABOUT'       the PDS containing "About This Gopher" info
  992.  MENU='GOPHER.MENU'         the initial gopher menu (sequential)
  993.  PARMS='GOPHER.PARMS'       the server startup file (sequential)
  994.  GPARM=                     the server EXEC parms (e.g. -d for debug)
  995.  
  996.  Note: if you specify GPARM='-D', a GGDEBUG DD must be included.
  997.  
  998.  You are strongly recommended to create 2 started tasks:  one for
  999.  non-REXX requests with MTFTASKS set to 8, and one for REXX requests
  1000.  with MTFTASKS set to 1 (because of TSO/E multitasking bugs).
  1001.  Give each a different port number in the GGPARMS configuration file
  1002.  allocated to it.  See sample below.
  1003.  
  1004.  15. Add the name of the Gopher server started task (the name as it
  1005.  appears in SYS1.PROCLIB, not necessarily "GOPHER") to the MVS TCPIP
  1006.  profile data set (or have your MVS TCP/IP system programmer do it).
  1007.  In the examples below, let's say you've called it GOPHSRV.  Add this
  1008.  in 2 places:
  1009.  
  1010.    (a) under AUTOLOG, so that TCP/IP will start the Gopher server
  1011.        automatically (a la inetd for unix) when a client connects.
  1012.        Just add the name to the list (e.g. GOPHSRV).
  1013.  
  1014.    (b) under PORT, so nobody can spoof the Gopher port.  The format
  1015.        here is:   70 TCP GOPHSRV
  1016.  
  1017.  Repeat both for whatever number of Gopher server started tasks you
  1018.  create (with different port numbers).
  1019.  
  1020. --------------------------------------------------------------------
  1021.  
  1022.  Note:  Make sure that the C/370 run time library is available,
  1023.  either in the system link list or in the STEPLIB concatenation,
  1024.  before attempting to run GOPHER.
  1025.  
  1026. --------------------------------------------------------------------
  1027.  
  1028. Following is an example of how to define two Gopher servers.
  1029.  
  1030. 'SYS1.PROCLIB(GOPHSRV)' - the primary gopher server (port 70)
  1031.                           will not run any REXX execs
  1032.  
  1033. //GOPHERD  PROC MODULE=GGSERVER,
  1034. //         STEPLIB='GOPHER.LOAD',
  1035. //         ACCESS='GOPHER.ACCESS(ACCESS)',
  1036. //         PARMS='GOPHER.ACCESS(PARMS)',
  1037. //         MENU='GOPHER.ACCESS(MENU)',
  1038. //         STDERR='*',
  1039. //         STDOUT='*',
  1040. //         GPARM=
  1041. //*
  1042. //GOPHERD  EXEC PGM=&MODULE,PARM='&GPARM'
  1043. //STEPLIB  DD   DISP=SHR,DSN=&STEPLIB
  1044. //SYSERR   DD   SYSOUT=&STDERR
  1045. //SYSPRINT DD   SYSOUT=&STDOUT
  1046. //SYSIN    DD   DUMMY
  1047. //GGDEBUG  DD   SYSOUT=*
  1048. //GGACCESS DD   DISP=SHR,DSN=&ACCESS
  1049. //GGPARMS  DD   DISP=SHR,DSN=&PARMS
  1050. //GGGOPHER DD   DISP=SHR,DSN=&MENU
  1051.  
  1052. 'SYS1.PROCLIB(GOPHSRV2)' - the secondary gopher server (port 1570)
  1053.                            will run REXX execs
  1054.  
  1055. //GOPHERD2 PROC MODULE=GGSERVER,
  1056. //         STEPLIB='GOPHER.LOAD',
  1057. //         EXECLIB='GOPHER.EXEC',
  1058. //         ACCESS='GOPHER.ACCESS(ACCESS2)',
  1059. //         PARMS='GOPHER.ACCESS(PARMS2)',
  1060. //         MENU='GOPHER.ACCESS(MENU2)',
  1061. //         VIO=VIO,
  1062. //         STDERR='*',
  1063. //         STDOUT='*',
  1064. //         GPARM=
  1065. //*
  1066. //GOPHERD2 EXEC PGM=IKJEFT01,DYNAMNBR=128, PARM='&MODULE &GPARM'
  1067. //STEPLIB  DD   DISP=SHR,DSN=&STEPLIB
  1068. //SYSEXEC  DD   DISP=SHR,DSN=&EXECLIB  /* needed for %-invoked execs */
  1069. //GGEXEC   DD   DISP=SHR,DSN=&EXECLIB
  1070. //SYSTSPRT DD   UNIT=&VIO,SPACE=(TRK,(100,100)),RECFM=VBA,LRECL=255
  1071. //SYSERR   DD   SYSOUT=&STDERR
  1072. //SYSPRINT DD   SYSOUT=&STDOUT
  1073. //SYSTSIN  DD   DUMMY
  1074. //SYSIN    DD   DUMMY
  1075. //GGDEBUG  DD   SYSOUT=*
  1076. //GGACCESS DD   DISP=SHR,DSN=&ACCESS
  1077. //GGPARMS  DD   DISP=SHR,DSN=&PARMS
  1078. //GGGOPHER DD   DISP=SHR,DSN=&MENU
  1079.  
  1080. 'GOPHER.ACCESS(PARMS)' - startup parameters used by the primary server
  1081.  
  1082. mtftasks  8    (this is the default)
  1083. port      70   (this is the default too)
  1084.  
  1085. 'GOPHER.ACCESS(PARMS2)'- startup parameters used by the secondary server
  1086.  
  1087. mtftasks  1       Force single threading to prevent TSO burpages
  1088. port      1570    Must be different from primary server's port
  1089.  
  1090. -----------------------------------------------------------------------
  1091.  
  1092. I have not included members ACCESS, ACCESS2, MENU and MENU2, but you
  1093. will find samples elsewhere in this distribution.  ACCESS and ACCESS2
  1094. can be the same, except that you don't need the REXX execs to be in
  1095. ACCESS since ACCESS can't run REXX execs.  MENU and MENU2 should be
  1096. the same, since you may want to configure various Gopher clients
  1097. on other machines to try both MVS servers, but it's up to you.
  1098.  
  1099. ./ ADD NAME=LINKC
  1100. //JOBNAME  JOB ACCOUNT,'NAME'
  1101. //*                                                                  */
  1102. //* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  1103. //*                                                                  */
  1104. //* This software is provided on an "AS IS" basis.  All warranties,  */
  1105. //* including the implied warranties of merchantability and fitness, */
  1106. //* are expressly denied.                                            */
  1107. //*                                                                  */
  1108. //* Provided this copyright notice is included, this software may    */
  1109. //* be freely distributed and not offered for sale.                  */
  1110. //*                                                                  */
  1111. //* Changes or modifications may be made and used only by the maker  */
  1112. //* of same, and not further distributed.  Such modifications should */
  1113. //* be mailed to the author for consideration for addition to the    */
  1114. //* software and incorporation in subsequent releases.               */
  1115. //*                                                                  */
  1116. //*********************************************************************
  1117. //*
  1118. //* Linkedit an executable Gopher load module.
  1119. //*
  1120. //GGLINK PROC LOADLIB='GOPHER.LOAD',             Executable load library
  1121. //            OBJLIB='GOPHER.INSTALL.OBJ',       Input object PDS
  1122. //            PLIBASE='SYS1.PLIBASE',            PL/1   link library
  1123. //            EDCBASE='SYS1.SEDCBASE',           C/370  link library
  1124. //            IBMBASE='SYS1.SIBMBASE',           PL/1+C common library
  1125. //            COMMTXT='TCPIP.COMMTXT',           TCP/IP link library
  1126. //            VIOUNIT=VIO,                       Temporary disk unit
  1127. //            OUTCLAS='*',                          SYSOUT class
  1128. //            LPARMS='LIST,LET,MAP',                Linkedit parameters
  1129. //            TEST=TEST                             TEST or NOTEST
  1130. //*
  1131. //LKED      EXEC PGM=IEWL,PARM='AMODE(31),RMODE(ANY),&TEST,&LPARMS'
  1132. //SYSPRINT  DD SYSOUT=&OUTCLAS
  1133. //DUMMYDD   DD DUMMY,DSN=&OBJLIB          needed to prevent JCL errors
  1134. //SYSLIB    DD DISP=SHR,DSN=&PLIBASE
  1135. //          DD DISP=SHR,DSN=&EDCBASE
  1136. //          DD DISP=SHR,DSN=&IBMBASE
  1137. //          DD DISP=SHR,DSN=&COMMTXT
  1138. //SYSLMOD   DD DISP=SHR,DSN=&LOADLIB
  1139. //SYSUT1    DD DSN=&&SYSUT1,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
  1140. //          SPACE=(32000,(30,30))
  1141. //*
  1142. //         PEND
  1143. //*
  1144. //*
  1145. //* Link GOPHER load module. Like SMP/E, expect return code 8 when
  1146. //* doing this from scratch.  Additional one-or-two-module links
  1147. //* will just replace the corresponding parts of the load module.
  1148. //*
  1149. //GGLINK EXEC GGLINK
  1150. //LKED.SYSLIN DD DISP=SHR,DSN=&OBJLIB(GGACCES)
  1151. //            DD DISP=SHR,DSN=&OBJLIB(GGALLOC)
  1152. //            DD DISP=SHR,DSN=&OBJLIB(GGASVC)
  1153. //            DD DISP=SHR,DSN=&OBJLIB(GGBARF)
  1154. //            DD DISP=SHR,DSN=&OBJLIB(GGBIN)
  1155. //            DD DISP=SHR,DSN=&OBJLIB(GGBKMGR)
  1156. //            DD DISP=SHR,DSN=&OBJLIB(GGCLIEN)
  1157. //            DD DISP=SHR,DSN=&OBJLIB(GGCLRTX)
  1158. //            DD DISP=SHR,DSN=&OBJLIB(GGCONN)
  1159. //            DD DISP=SHR,DSN=&OBJLIB(GGCSO)
  1160. //            DD DISP=SHR,DSN=&OBJLIB(GGDBM)
  1161. //            DD DISP=SHR,DSN=&OBJLIB(GGDFAIL)
  1162. //            DD DISP=SHR,DSN=&OBJLIB(GGDIR)
  1163. //            DD DISP=SHR,DSN=&OBJLIB(GGDISC)
  1164. //            DD DISP=SHR,DSN=&OBJLIB(GGDISPL)
  1165. //            DD DISP=SHR,DSN=&OBJLIB(GGDSOPT)
  1166. //            DD DISP=SHR,DSN=&OBJLIB(GGDUMP)
  1167. //            DD DISP=SHR,DSN=&OBJLIB(GGESRVR)
  1168. //            DD DISP=SHR,DSN=&OBJLIB(GGFREEM)
  1169. //            DD DISP=SHR,DSN=&OBJLIB(GGFTP)
  1170. //            DD DISP=SHR,DSN=&OBJLIB(GGGETDS)
  1171. //            DD DISP=SHR,DSN=&OBJLIB(GGGETM)
  1172. //            DD DISP=SHR,DSN=&OBJLIB(GGGOFOR)
  1173. //            DD DISP=SHR,DSN=&OBJLIB(GGGSRVL)
  1174. //            DD DISP=SHR,DSN=&OBJLIB(GGIERR)
  1175. //            DD DISP=SHR,DSN=&OBJLIB(GGIGET)
  1176. //            DD DISP=SHR,DSN=&OBJLIB(GGINFO)
  1177. //            DD DISP=SHR,DSN=&OBJLIB(GGISPF)
  1178. //            DD DISP=SHR,DSN=&OBJLIB(GGIVGET)
  1179. //            DD DISP=SHR,DSN=&OBJLIB(GGIVPUT)
  1180. //            DD DISP=SHR,DSN=&OBJLIB(GGMENU)
  1181. //            DD DISP=SHR,DSN=&OBJLIB(GGMTFER)
  1182. //            DD DISP=SHR,DSN=&OBJLIB(GGOUTS)
  1183. //            DD DISP=SHR,DSN=&OBJLIB(GGOUTTX)
  1184. //            DD DISP=SHR,DSN=&OBJLIB(GGPMSG)
  1185. //            DD DISP=SHR,DSN=&OBJLIB(GGPROC)
  1186. //            DD DISP=SHR,DSN=&OBJLIB(GGREXX)
  1187. //            DD DISP=SHR,DSN=&OBJLIB(GGSLEEP)
  1188. //            DD DISP=SHR,DSN=&OBJLIB(GGSOCKT)
  1189. //            DD DISP=SHR,DSN=&OBJLIB(GGSOPT)
  1190. //            DD DISP=SHR,DSN=&OBJLIB(GGTEMP)
  1191. //            DD DISP=SHR,DSN=&OBJLIB(GGTNET)
  1192. //            DD DISP=SHR,DSN=&OBJLIB(GGTSO)
  1193. //            DD DISP=SHR,DSN=&OBJLIB(GGTYPE)
  1194. //            DD DISP=SHR,DSN=&OBJLIB(GGUNALC)
  1195. //            DD DISP=SHR,DSN=&OBJLIB(GGVIEW)
  1196. //            DD DISP=SHR,DSN=&OBJLIB(GGVTX)
  1197. //            DD DISP=SHR,DSN=&OBJLIB(GGWAIS)
  1198. //            DD DISP=SHR,DSN=&OBJLIB(GGWHOIS)
  1199. //            DD DISP=SHR,DSN=&OBJLIB(GGWTO)
  1200. //            DD DISP=SHR,DSN=&OBJLIB(GGXTX)
  1201. //            DD *
  1202.  ENTRY   CEESTART
  1203.  NAME    GGCLIENT(R)
  1204. /*
  1205. ./ ADD NAME=LINKS
  1206. //JOBNAME  JOB ACCOUNT,'NAME'
  1207. //*                                                                  */
  1208. //* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  1209. //*                                                                  */
  1210. //* This software is provided on an "AS IS" basis.  All warranties,  */
  1211. //* including the implied warranties of merchantability and fitness, */
  1212. //* are expressly denied.                                            */
  1213. //*                                                                  */
  1214. //* Provided this copyright notice is included, this software may    */
  1215. //* be freely distributed and not offered for sale.                  */
  1216. //*                                                                  */
  1217. //* Changes or modifications may be made and used only by the maker  */
  1218. //* of same, and not further distributed.  Such modifications should */
  1219. //* be mailed to the author for consideration for addition to the    */
  1220. //* software and incorporation in subsequent releases.               */
  1221. //*                                                                  */
  1222. //*********************************************************************
  1223. //*
  1224. //* Linkedit an executable Gopher load module.
  1225. //*
  1226. //GGLINK PROC LOADLIB='GOPHER.LOAD',             Executable load library
  1227. //            OBJLIB='GOPHER.INSTALL.OBJ',       Input object PDS
  1228. //            PLIBASE='SYS1.PLIBASE',            PL/1   link library
  1229. //            EDCBASE='SYS1.SEDCBASE',           C/370  link library
  1230. //            IBMBASE='SYS1.SIBMBASE',           PL/1+C common library
  1231. //            COMMTXT='TCPIP.COMMTXT',           TCP/IP link library
  1232. //            VIOUNIT=VIO,                       Temporary disk unit
  1233. //            OUTCLAS='*',                          SYSOUT class
  1234. //            LPARMS='LIST,LET,MAP',                Linkedit parameters
  1235. //            TEST=TEST                             TEST or NOTEST
  1236. //*
  1237. //LKED      EXEC PGM=IEWL,PARM='AMODE(31),RMODE(ANY),&TEST,&LPARMS'
  1238. //SYSPRINT  DD SYSOUT=&OUTCLAS
  1239. //DUMMYDD   DD DUMMY,DSN=&OBJLIB          needed to prevent JCL errors
  1240. //SYSLIB    DD DISP=SHR,DSN=&PLIBASE
  1241. //          DD DISP=SHR,DSN=&EDCBASE
  1242. //          DD DISP=SHR,DSN=&IBMBASE
  1243. //          DD DISP=SHR,DSN=&COMMTXT
  1244. //SYSLMOD   DD DISP=SHR,DSN=&LOADLIB
  1245. //SYSUT1    DD DSN=&&SYSUT1,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
  1246. //          SPACE=(32000,(30,30))
  1247. //*
  1248. //         PEND
  1249. //*
  1250. //* Link GOPHER server subtask module.
  1251. //*
  1252. //GGLINK EXEC GGLINK
  1253. //LKED.SYSLIN DD DISP=SHR,DSN=&OBJLIB(GGSTASK)
  1254. //            DD DISP=SHR,DSN=&OBJLIB(GGACCES)
  1255. //            DD DISP=SHR,DSN=&OBJLIB(GGALLOC)
  1256. //            DD DISP=SHR,DSN=&OBJLIB(GGASVC)
  1257. //            DD DISP=SHR,DSN=&OBJLIB(GGBARF)
  1258. //            DD DISP=SHR,DSN=&OBJLIB(GGDFAIL)
  1259. //            DD DISP=SHR,DSN=&OBJLIB(GGDUMP)
  1260. //            DD DISP=SHR,DSN=&OBJLIB(GGFREEM)
  1261. //            DD DISP=SHR,DSN=&OBJLIB(GGFTP)
  1262. //            DD DISP=SHR,DSN=&OBJLIB(GGGETM)
  1263. //            DD DISP=SHR,DSN=&OBJLIB(GGGSRVL)
  1264. //            DD DISP=SHR,DSN=&OBJLIB(GGIERR)
  1265. //            DD DISP=SHR,DSN=&OBJLIB(GGISPF)
  1266. //            DD DISP=SHR,DSN=&OBJLIB(GGIVPUT)
  1267. //            DD DISP=SHR,DSN=&OBJLIB(GGOUTS)
  1268. //            DD DISP=SHR,DSN=&OBJLIB(GGPMSG)
  1269. //            DD DISP=SHR,DSN=&OBJLIB(GGPROC)
  1270. //            DD DISP=SHR,DSN=&OBJLIB(GGREXX)
  1271. //            DD DISP=SHR,DSN=&OBJLIB(GGSOCKT)
  1272. //            DD DISP=SHR,DSN=&OBJLIB(GGTEMP)
  1273. //            DD DISP=SHR,DSN=&OBJLIB(GGTSO)
  1274. //            DD DISP=SHR,DSN=&OBJLIB(GGTYPE)
  1275. //            DD DISP=SHR,DSN=&OBJLIB(GGUNALC)
  1276. //            DD DISP=SHR,DSN=&OBJLIB(GGWTO)
  1277. //            DD *
  1278.  INCLUDE SYSLIB(IUCVFORC)
  1279.  INCLUDE SYSLIB(EDCMTFS)
  1280.  ENTRY   CEESTART
  1281.  NAME    GGSTASK(R)
  1282. /*
  1283. //*
  1284. //* Link GOPHER server main module.
  1285. //*
  1286. //GGLINKS EXEC GGLINK
  1287. //LKED.SYSLIN DD DISP=SHR,DSN=&OBJLIB(GGSERVE)
  1288. //            DD DISP=SHR,DSN=&OBJLIB(GGACCES)
  1289. //            DD DISP=SHR,DSN=&OBJLIB(GGFREEM)
  1290. //            DD DISP=SHR,DSN=&OBJLIB(GGGETM)
  1291. //            DD DISP=SHR,DSN=&OBJLIB(GGMTFER)
  1292. //            DD *
  1293.  ENTRY   CEESTART
  1294.  NAME    GGSERVER(R)
  1295. /*
  1296. ./ ADD NAME=LINKX
  1297. //JOBNAME  JOB ACCOUNT,'NAME'
  1298. //*                                                                  */
  1299. //* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  1300. //*                                                                  */
  1301. //* This software is provided on an "AS IS" basis.  All warranties,  */
  1302. //* including the implied warranties of merchantability and fitness, */
  1303. //* are expressly denied.                                            */
  1304. //*                                                                  */
  1305. //* Provided this copyright notice is included, this software may    */
  1306. //* be freely distributed and not offered for sale.                  */
  1307. //*                                                                  */
  1308. //* Changes or modifications may be made and used only by the maker  */
  1309. //* of same, and not further distributed.  Such modifications should */
  1310. //* be mailed to the author for consideration for addition to the    */
  1311. //* software and incorporation in subsequent releases.               */
  1312. //*                                                                  */
  1313. //*********************************************************************
  1314. //*
  1315. //* Linkedit auxiliary Gopher executables.
  1316. //*
  1317. //GGLINK PROC LOADLIB='GOPHER.LOAD',             Executable load library
  1318. //            OBJLIB='GOPHER.INSTALL.OBJ',       Input object PDS
  1319. //            PLIBASE='SYS1.PLIBASE',            PL/1   link library
  1320. //            EDCBASE='SYS1.SEDCBASE',           C/370  link library
  1321. //            IBMBASE='SYS1.SIBMBASE',           PL/1+C common library
  1322. //            EDCSPC='SYS1.SEDCSPC',             C/370 sysprog library
  1323. //            VIOUNIT=VIO,                       Temporary disk unit
  1324. //            OUTCLAS='*',                          SYSOUT class
  1325. //            LPARMS='LIST,LET,MAP',                Linkedit parameters
  1326. //            TEST=TEST                             TEST or NOTEST
  1327. //*
  1328. //LKED      EXEC PGM=IEWL,PARM='AMODE(31),RMODE(ANY),&TEST,&LPARMS'
  1329. //SYSPRINT  DD SYSOUT=&OUTCLAS
  1330. //DUMMYDD   DD DUMMY,DSN=&OBJLIB          needed to prevent JCL errors
  1331. //SYSLIB    DD DISP=SHR,DSN=&EDCSPC
  1332. //          DD DISP=SHR,DSN=&PLIBASE
  1333. //          DD DISP=SHR,DSN=&EDCBASE
  1334. //          DD DISP=SHR,DSN=&IBMBASE
  1335. //SYSLMOD   DD DISP=SHR,DSN=&LOADLIB
  1336. //SYSUT1    DD DSN=&&SYSUT1,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
  1337. //          SPACE=(32000,(30,30))
  1338. //*
  1339. //         PEND
  1340. //*
  1341. //* Link GOPHER client and server auxiliary modules.
  1342. //*
  1343. //XGALLOC EXEC GGLINK
  1344. //LKED.SYSLIN  DD DISP=SHR,DSN=&OBJLIB(XGALLOC)
  1345. //             DD DISP=SHR,DSN=&OBJLIB(GGASVC)
  1346. //             DD *
  1347.  ENTRY    XGALLOC
  1348.  NAME     XGALLOC(R)
  1349. /*
  1350. //XGSLEEP EXEC GGLINK
  1351. //LKED.SYSLIN  DD DISP=SHR,DSN=&OBJLIB(XGSLEEP)
  1352. //             DD DISP=SHR,DSN=&OBJLIB(GGSLEEP)
  1353. //             DD DISP=SHR,DSN=&OBJLIB(GGASVC)
  1354. //             DD *
  1355.  ENTRY    CEESTART
  1356.  NAME     XGSLEEP(R)
  1357. /*
  1358. //XGWTO   EXEC GGLINK
  1359. //LKED.SYSLIN  DD DISP=SHR,DSN=&OBJLIB(XGWTO)
  1360. //             DD DISP=SHR,DSN=&OBJLIB(GGWTO)
  1361. //             DD DISP=SHR,DSN=&OBJLIB(GGASVC)
  1362. //             DD *
  1363.  ENTRY    CEESTART
  1364.  NAME     XGWTO(R)
  1365. /*
  1366. ./ ADD NAME=MENU
  1367. gopher_menu
  1368.  
  1369. TYPE=FILE
  1370. NAME=About This Gopher
  1371. PATH=DD:GGABOUT(ABOUT)
  1372. HOST=+
  1373. END
  1374.  
  1375. TYPE=FILE
  1376. NAME=TSO HELP (Sample Illustrating the REXX Interface)
  1377. PATH=EXEC:TSOHELP
  1378. HOST=+
  1379. END
  1380.  
  1381. TYPE=DIRECTORY
  1382. NAME=Library/Information Services
  1383. PATH=SYS0008.GOPHER.LIBRARY(LIBRS)
  1384. HOST=MVS.UDEL.EDU
  1385. END
  1386.  
  1387. TYPE=TELNET
  1388. NAME=UDINFO - University of Delaware Information
  1389. HOST=UDINFO.UDEL.EDU
  1390. END
  1391.  
  1392. TYPE=DIRECTORY
  1393. NAME=Network and System Services Computer Systems
  1394. PATH=SYS0008.GOPHER.DIR(UDTELNET)
  1395. HOST=MVS.UDEL.EDU
  1396. END
  1397.  
  1398. TYPE=DIRECTORY
  1399. NAME=Weather Across the Country
  1400. PATH=1/Weather
  1401. HOST=mermaid.micro.umn.edu
  1402. PORT=150
  1403. END
  1404.  
  1405. TYPE=DIRECTORY
  1406. NAME=Other Gopher and Information Servers
  1407. PATH=1/Other Gopher and Information Servers
  1408. HOST=gopher.micro.umn.edu
  1409. END
  1410.  
  1411. TYPE=DIRECTORY
  1412. NAME=How to use BITNET LISTSERV Servers
  1413. PATH=SYS0008.GOPHER.DIR(LISTSERV)
  1414. HOST=MVS.UDEL.EDU
  1415. END
  1416.  
  1417. TYPE=DIRECTORY
  1418. NAME=University of Delaware Newspapers
  1419. PATH=SYS0008.GOPHER.DIR(PAPERS)
  1420. HOST=MVS.UDEL.EDU
  1421. END
  1422.  
  1423. /*
  1424. ./ ADD NAME=PARMS
  1425. !
  1426. ! MVS Gopher Sample Startup Parameter File
  1427. !
  1428. ! All entries in this file have the format:   variable value comments
  1429. !
  1430. ! These are the possible values and their default settings:
  1431. !
  1432. ! mtftasks 1    Number of concurrent subtasks to handle client requests
  1433. ! port     70   The TCP port number by which clients connect
  1434. ! qlength  20   Queue length for TCP server listen function
  1435. ! timeout  60   Connection timeout specified when socket is closed
  1436. ! domain   .DRAPER.COM     The suffix to be appende to bald host names
  1437.  
  1438. mtftasks 1    Number of concurrent subtasks to handle client requests
  1439. port     70   The TCP port number by which clients connect
  1440. qlength  20   Queue length for TCP subtask creation
  1441. timeout  60   Connection timeout specified when socket is closed
  1442.  
  1443. ./ ADD NAME=SECURE
  1444. The following discussion is included by permission of the participants.
  1445.  
  1446. From: SEB1525@MVS.draper.com (Steve Bacher)
  1447. Subject: Secure Rexx?
  1448. Organization: Draper Laboratory
  1449. Date: Fri, 19 Nov 1993 16:13:00 GMT
  1450.  
  1451. Has anyone given any thought to what would be needed to evaluate the
  1452. "security" of REXX?
  1453.  
  1454. I'm thinking of what you'd have to do to prove that it was OK to have
  1455. a REXX script running behind an anonymous FTP or gopher server, for
  1456. example.  We know that commands like vi and utilities like PostScript
  1457. are questionable because they provide shell escapes.  What could you
  1458. say about a REXX script on such a system?
  1459.  
  1460. To start, I'd suggest that you would want to disable the INTERPRET
  1461. statement, so that a remote user could not cause a REXX exec to
  1462. invoke arbitrary code.  You might also want to restrict the ADDRESS
  1463. instruction, perhaps limiting it to a set of known address environments.
  1464.  
  1465. Any other ideas?  Apologies if this question is somewhat Unix-centric.
  1466.  
  1467.  
  1468. --
  1469. Steve Bacher (Batchman)                 Draper Laboratory
  1470. Internet: seb@draper.com                Cambridge, MA, USA
  1471.  
  1472.  
  1473. Date: Fri, 19 Nov 1993 13:56:11 -0500
  1474. From: "Stephen E. Bacher" <seb@DRAPER.COM>
  1475. Subject: Re: Secure Rexx?
  1476.  
  1477. I would rephrase the question "Is a given program written in
  1478. language X secure?"  The answer can be one of "yes", "no", or
  1479. "cannot be determined".  Only programs that returned answer
  1480. number one would be eligible for secure environments.
  1481.  
  1482. Keep in mind that security is a relative term.  Since we cannot
  1483. prove beyond the shadow of a doubt that something is 100% impregnable,.
  1484. one must adopt a "reasonable person" approach.  Just as you wouldn't
  1485. protect your house with the same arsenal as is used to protect our
  1486. nuclear launchers.
  1487.  
  1488. What I mean is that if you know that if you connect to a gopher server
  1489. at foo.bar.edu, say, and you know that if you pass it a selector string
  1490. of "exec:open-sesame:some-rexx-script", the server will execute the
  1491. script some-rexx-script with a parameter of open-sesame with the
  1492. privileges of the gopher daemon at foo.bar.edu.  Depending on the
  1493. powers of that daemon, it could go off and execute a command that
  1494. updated your college transcript, or something.  That is kind of
  1495. farfetched, and suggests that the gopher was not set up very securely
  1496. in and of itself, but there are all kinds of possibilities.
  1497.  
  1498. One thing that a gopher daemon MIGHT be able to do is to update its
  1499. own gopher menu tree.  That could be a risk.
  1500.  
  1501. Note that the script might not even be one set up by the gopher guys.
  1502. Of course, we'll cover that particular hole.  Note that I don't want
  1503. to go into more detail about just how much security is theirs and
  1504. how much is, or will be, ours - there will be time for that when we
  1505. release our mods to the UMn gopher server (at least I hope we do).
  1506.  
  1507.  
  1508.  
  1509. From: Anders Christensen <anders@lise.unit.no>
  1510. Date: Tue, 23 Nov 1993 22:04:23 +0100
  1511. To: "Stephen E. Bacher" <seb@draper.com>
  1512. Subject: Re: Secure Rexx?
  1513.  
  1514.  
  1515. > I am specifically concerned about using REXX scripts in a server
  1516. > environment where they will be in the role of delivering publicly
  1517. > available information.  Any user could pass a request to have the
  1518. > server run that REXX exec, so it is imperative that what the exec
  1519. > can do be constrained.
  1520.  
  1521. I'd say that it's somewhat impossible to have a secure Rexx script,
  1522. the reason is this: In addition to INTERPRET you would have to disable
  1523. several other constructs:
  1524.  
  1525.  1) The ADDRESS keyword instruction and commands should be disabled. As
  1526.     long as one can do things like:
  1527.  
  1528.       address system 'echo' var '>/tmp/foo.rexx; rexx /tmp/foo.rexx'
  1529.  
  1530.     then ADDRESS is just as insecure as INTERPRET.
  1531.  
  1532.  2) For language level 3.50 and above, LINEOUT() and CHAROUT() should
  1533.     be disabled. Consider the possibility that the program is fooled
  1534.     to run code writing to files related to security (.rhosts,
  1535.     .forward, .login, etc). That could easily be the first step of an
  1536.     attack at the account. Besides:
  1537.  
  1538.       lineout('myfile',var); say 'myfile'()
  1539.  
  1540.     is just as insecure as INTERPRET.
  1541.  
  1542.  3) There are also some files which should not be readable for the
  1543.     whole world. Security is related to files that contain keys for
  1544.     encryption (e.g. .xauthority). Thus, maybe LINEIN() and CHARIN()
  1545.     should be restricted too.
  1546.  
  1547. This results in a Rexx interpreter that cannot execute commands, or
  1548. read or write files. Such a mode is of very limited value. There may
  1549. be other things to disable too:
  1550.  
  1551.  4) SAA REXX contains rxfuncadd() and friends in order to dynamically
  1552.     load code into the intepreter. It provides lots of 'interesting'
  1553.     possibilties.
  1554.  
  1555.  5) External functions should perhaps be disabled. Although you can
  1556.     verify the contents of the external function like you verify the
  1557.     contents of the main program, you cannot enable external functions
  1558.     that are not Rexx scripts.
  1559.  
  1560.  6) Most implementations contains many extra builtin functions, some
  1561.     which may be used as security backdoors. Just consider what can be
  1562.     done with the DIAG() bifs under CMS. In the same manner, you'd
  1563.     have to disable OPTIONS, since it too, is able to perform random
  1564.     operations, depending only on the implementation of the
  1565.     interpreter.
  1566.  
  1567.  7) The VALUE() bif can be dangerous when used with it's third
  1568.     parameter, since under some implementations it can be used to set
  1569.     environment variables. Suppose you have a 'secure' command, but
  1570.     the user is able to set PATH (under Unix) ...
  1571.  
  1572.  8) Interactive tracing ... really lots of interesting possiblities!
  1573.     (And remember to disable TRACE() too!)
  1574.  
  1575.  9) You have to insulate the stack from effects done by the program.
  1576.     Suppose the user just pushes commands to the stack and exits. Most
  1577.     Unix version would not suffer from this, but CMS could probably be
  1578.     fooled.
  1579.  
  1580. I believe that the resulting interpreter would be fairly useless. The
  1581. clue is probably to write secure _scripts_, rather than secure
  1582. _interpreters_; and the main features are:
  1583.  
  1584.  1) Never run any external functions or commands that might be
  1585.     compromised.
  1586.  
  1587.  2) Check (and double-check) the format and contents of all data read
  1588.     from external sources, like files, the keyboard, parameter- and
  1589.     option-values, or the network.
  1590.  
  1591. On the other hand, there are several 'features' about Rexx that makes
  1592. me nervous with respect to so-called secure programming, or provable
  1593. programs. Consider the following part of a long Rexx program:
  1594.  
  1595.      'test -f /etc/passwd'
  1596.      if rc=0 then
  1597.          do_something
  1598.  
  1599. The do_something part may perfectly well be called also whenever rc
  1600. was something else than zero. Just assume CALL ON HALT, and the
  1601. following code somewhere else:
  1602.  
  1603.      halt:
  1604.          rc = 0   /* or more likely: a command */
  1605.          return
  1606.  
  1607. Consequently, the value of RC becomes undefined at all clause
  1608. boundaries (strictly speaking). Thus, one can not use CALL ON HALT in
  1609. 'secure' scripts. Another source of constant despair is arithmetic.
  1610. Consider the seemingly good-natured loop (where an evil eternal loop
  1611. may be lurking!):
  1612.  
  1613.      do i=5 to 15
  1614.         say i
  1615.         end
  1616.  
  1617. How can this loop become non-ending? By setting NUMERIC DIGITS to 1.
  1618. When i has the value 9 and is incremented, it gets the values 1E1.
  1619. When 1E1 is incremented by 1, it becomes 1E1 ... and thus the eternal
  1620. loop. Therefore, if you want to prove a Rexx program, you have to
  1621. guard against all cases where this may happen: either when NUMERIC
  1622. DIGITS is too low, or when the control variable becomes to high.
  1623. Frankly, this is completely impossible to handle.
  1624.  
  1625. These are some of the examples I stumbled across when I was writing
  1626. the trip test.  ... Rexx is a very strange languages ... :-)
  1627.  
  1628. Regards,
  1629. -anders
  1630.  
  1631.  
  1632. ./ ENDUP
  1633. ?!
  1634. //ABOUT    EXEC MDLOAD,BS='6160',TRK1='5',TRK2='1',TO='ABOUT'
  1635. //SYSIN    DD   DATA,DLM='?!'
  1636. ./ ADD NAME=ABOUT
  1637. gopher_menu
  1638.  
  1639. TYPE=FILE
  1640. NAME=What Is Gopher?
  1641. PATH=(ABOUTW)
  1642. HOST=+
  1643. END
  1644.  
  1645. TYPE=FILE
  1646. NAME=Gopher FAQ (Frequently Asked Questions) List
  1647. PATH=(FAQ)
  1648. HOST=+
  1649. END
  1650.  
  1651. TYPE=DIRECTORY
  1652. NAME=Using The Gopher MVS Client
  1653. PATH=(ABOUTC)
  1654. HOST=+
  1655. END
  1656.  
  1657. TYPE=DIRECTORY
  1658. NAME=Administering the Gopher MVS Server
  1659. PATH=(ABOUTS)
  1660. HOST=+
  1661. END
  1662.  
  1663.  
  1664. ./ ADD NAME=ABOUTC
  1665. gopher_menu
  1666.  
  1667. TYPE=FILE
  1668. NAME=Overview - Using Gopher on MVS
  1669. PATH=(ABOUTCO)
  1670. HOST=+
  1671. END
  1672.  
  1673. TYPE=FILE
  1674. NAME=Directory Mode - Viewing a Gopher Directory
  1675. PATH=(ABOUTCD)
  1676. HOST=+
  1677. END
  1678.  
  1679. TYPE=FILE
  1680. NAME=File Mode - Browsing a Gopher File
  1681. PATH=(ABOUTCF)
  1682. HOST=+
  1683. END
  1684.  
  1685. TYPE=FILE
  1686. NAME=Index Mode - Executing a Gopher Query
  1687. PATH=(ABOUTCQ)
  1688. HOST=+
  1689. END
  1690.  
  1691. TYPE=DIRECTORY
  1692. NAME=Customizing Your Gopher Startup
  1693. PATH=(ABOUTCS)
  1694. HOST=+
  1695. END
  1696.  
  1697. TYPE=FILE
  1698. NAME=MVS Gopher Frequently Asked Questions (FAQ) List
  1699. PATH=(MVSFAQ)
  1700. HOST=+
  1701. END
  1702.  
  1703. ./ ADD NAME=ABOUTCD
  1704. Directory Mode - Viewing a Gopher Directory
  1705.  
  1706. When you are viewing a Gopher menu (directory), you may perform any
  1707. of the following actions:
  1708.  
  1709.  * Scroll up and down via the normal ISPF UP and DOWN commands or PFK's
  1710.    to view all the items in the menu
  1711.  
  1712.  * Scroll left and right via the normal ISPF LEFT and RIGHT commands or
  1713.    PFK's to be able to read the entirety of long names on the menu
  1714.  
  1715.  * Type one of the following letters to the left of a menu item and
  1716.    press ENTER:
  1717.  
  1718.    S - Select the item for viewing or processing
  1719.    E - Extract the contents of the item to a file
  1720.    P - Print the contents of the item to a system printer
  1721.    B - Save the entry as a bookmark (in a bookmark file)
  1722.    D - Delete this entry from the bookmark file *** not yet supported **
  1723.    Q - Display the item as a file, even if it isn't ("Query")
  1724.    I - Display the internal Information of the menu item
  1725.  
  1726.  * Enter one of the following commands on the command line:
  1727.  
  1728.    MENU - load a data set containing Gopher menu entries (e.g. bookmark)
  1729.    OPTions - set client processing options
  1730.    QUIT - exit Gopher entirely
  1731.  
  1732.    or any standard ISPF command.
  1733.  
  1734. When you select an item, what happens next depends on the type of the
  1735. item you have selected.
  1736.  
  1737. For a File type, you are placed in browse mode on the data.
  1738.  
  1739. For a Directory type, you get another Gopher menu (directory).
  1740.  
  1741. For an Index type, you see a panel asking you to enter a search string
  1742. of some kind, after which a Gopher menu (directory) of results appears.
  1743.  
  1744. For a TELNET type, a telnet session is started, for which you must
  1745. enter a login name at the appropriate time.
  1746.  
  1747. For a TN3270 type, a tn3270 session is started, for which you must
  1748. enter a login name at the appropriate time.
  1749.  
  1750. For a CSO type, you are placed in a phonebook lookup session.
  1751.  
  1752. For a BookManager type, you are placed in BookManager READ/MVS (tm).
  1753.  
  1754. For a binary type, you are placed in browse mode on the binary data.
  1755. This is generally not useful, though.
  1756.  
  1757. ./ ADD NAME=ABOUTCF
  1758. Browse Mode - Viewing a File in Gopher
  1759.  
  1760. When you are viewing a Gopher file, you are placed in "browse mode".
  1761. This is very similar to normal ISPF data set browse, except that:
  1762.  
  1763.  * In addition to most browse commands, you may issue any of the
  1764.    following commands:
  1765.  
  1766.    EXT or EXTRACT   - copy the current contents to a file
  1767.    PRT or PRNT      - print the current data to SYSOUT.
  1768.    BOOK or BOOKMARK - Save the entry as a bookmark (in a bookmark file).
  1769.    INFO             - Display the internal Information for this item
  1770.    OPT or OPTIONs   - Set Gopher client processing options
  1771.    QUIT             - terminates Gopher entirely.
  1772.  
  1773.    Note that PRT is different from PRINT, which is a built-in ISPF
  1774.    command that prints the current physical screen image.
  1775.  
  1776.  * The following ISPF browse commands are the only ones that are
  1777.    ***not*** supported under GOPHER:
  1778.  
  1779.   HEX
  1780.   BROWSE
  1781.   SUBMIT
  1782.   LOCATE .label
  1783.   .<string> (to assign a label)
  1784.   FIND P'generic-string'
  1785.   DISPLAY CC/NOCC
  1786.  
  1787. ./ ADD NAME=ABOUTCO
  1788. The following is modified from Allan Tuchman's XGOPHER help.
  1789.  
  1790. Gopher on MVS is an ISPF dialog interface to the Gopher
  1791. information delivery system from the University of Minnesota.
  1792.  
  1793. If your Gopher environment has not been customized by the system
  1794. programmer who installed it, Gopher will start up with an initial
  1795. panel asking you to specify the name of the Gopher server host, as
  1796. well as some other fields which you would normally leave alone.
  1797. Otherwise, you will see the main menu of the default Gopher server
  1798. defined at your installation.
  1799.  
  1800. Assuming that the top-level path points to a valid Gopher menu,
  1801. the initial display will show the top level directory of
  1802. gopher information available.  Selecting an item from this
  1803. list will fetch the contents of a file, subdirectory, or
  1804. other information.  The directory display may be updated to
  1805. show the new subdirectory.
  1806.  
  1807. To select an item, type "S" in front of it and press ENTER.  This
  1808. puts you into ISPF BROWSE mode on the text of the item.  You may also
  1809. type "Q" in front of an item to see it in text format even if it is a
  1810. directory.  Or you may type "E" in front of it to extract it into a
  1811. file, or "P" to print it - but you may do this more easily via the
  1812. EXTract command or PRT command from within BROWSE.
  1813.  
  1814. Type "I" in front of the item to view the internal menu information.
  1815. This is sometimes helpful if you are not sure why you are having
  1816. trouble accessing an item.
  1817.  
  1818. Type "B" in front of the item to save it in a bookmark file.  You will
  1819. be prompted to supply the name of a bookmark data set; the default is
  1820. GOPHER.BOOKMARK under your TSO prefix.  You may retrieve bookmarks at a
  1821. later date by typing "MENU GOPHER.BOOKMARK" - or whatever data set name
  1822. you used - or you can put a pointer to the bookmark data set in your
  1823. private Gopher menu (for which you need to learn how to edit your
  1824. GOPHERRC file).
  1825.  
  1826. Some gopher file types are not supported by the current client.
  1827. These will not appear on your menus.  Furthermore, you may not
  1828. be permitted to access some items, depending upon the server
  1829. and the host from which you are trying to access them.  These
  1830. restrictions do not apply to local mode, where you can access
  1831. anything that you have local permission to read.
  1832.  
  1833. The Gopher MVS client is written by Steve Bacher at Draper Laboratory
  1834. (copyright 1992).
  1835.  
  1836. ./ ADD NAME=ABOUTCQ
  1837. Index Mode - Executing a Gopher Query
  1838.  
  1839. When you select a Gopher "index" or "query" option, you are expected
  1840. to enter some sort of search string.  A typical application is a
  1841. phone book lookup, or a keyword search of some archive.
  1842.  
  1843. You will see a popup panel (or just a plain panel if you are running
  1844. an old version of ISPF) that asks you to enter a search string.  Just
  1845. type it in and press ENTER.  What format the string needs to be in
  1846. depends totally on the service that is going to process it.
  1847.  
  1848. What you get back is a directory with a list of "hits" or whatever
  1849. is appropriate for the data you requested.  This is just like any
  1850. other Gopher directory.
  1851.  
  1852. With the original Gopher protocol, there was no mechanism for
  1853. defining an index/query that returned file data immediately.
  1854. MVS Gopher supports an experimental "whois" type that does this.
  1855. However, since it was only spottily implemented by other Gophers,
  1856. and not always the right way (in the humble opinion of the author
  1857. or the MVS client), it is not likely that you will see such an option
  1858. on your Gopher screen.
  1859.  
  1860. ./ ADD NAME=ABOUTCS
  1861. gopher_menu
  1862.  
  1863. Type=FILE
  1864. Name=Customizing Your Gopher Startup
  1865. Path=(ABOUTCSC)
  1866. Host=+
  1867. End
  1868.  
  1869. Type=FILE
  1870. Name=What Happens When You Start Up Gopher
  1871. Path=(ABOUTCSW)
  1872. Host=+
  1873. End
  1874.  
  1875. Type=FILE
  1876. Name=Requesting Local (Serverless) Access
  1877. Path=(ABOUTCSL)
  1878. Host=+
  1879. End
  1880.  
  1881. Type=FILE
  1882. Name=The GOPHERRC File
  1883. Path=(ABOUTCSR)
  1884. Host=+
  1885. End
  1886.  
  1887. Type=FILE
  1888. Name=Defining GOPHER Menus
  1889. Path=(ABOUTCSM)
  1890. Host=+
  1891. End
  1892.  
  1893. Type=DIRECTORY
  1894. Name=REXX Exec Interface
  1895. Path=(ABOUTR)
  1896. Host=+
  1897. End
  1898.  
  1899. ./ ADD NAME=ABOUTCSC
  1900.  
  1901. =======================================================================
  1902.  
  1903.  Customizing Your Gopher Startup
  1904.  
  1905. =======================================================================
  1906.  
  1907.  When you use the GOPHER client, information about your use of GOPHER
  1908.  is stored in a data set called GOPHERRC.  If you don't have one,
  1909.  GOPHER will create it for you.
  1910.  
  1911.  Your default startup menu will contain a single item pointing to a
  1912.  GOPHER server on your host system, whether such a server is available
  1913.  or not.  However, you can ask GOPHER to display a different startup
  1914.  menu for you.  This startup menu may have entries for the GOPHER
  1915.  server on the host system and one for your own private (local) data,
  1916.  which the GOPHER client accesses without querying a server.
  1917.  
  1918.  To get GOPHER to set up a different startup menu, you must edit the
  1919.  GOPHERRC file.  Note that you may set up the GOPHER startup menu to
  1920.  include a pointer to your local data - but you have to create that
  1921.  local data in order to use it.
  1922.  
  1923.  Editing the GOPHERRC file should be easy.  Just follow the
  1924.  instructions in the comments of the file itself.  For information
  1925.  about the contents of GOPHERRC, see "The GOPHERRC File."
  1926.  
  1927.  You may also specify a different startup file when you invoke
  1928.  the MVS GOPHER client via the INITFILE keyword - e.g.
  1929.  
  1930.    GOPHER INITFILE(SOME.OTHER.RC)
  1931.  
  1932.  If the data set does not yet exist, it will be created.  You may
  1933.  then edit that data set without altering your usual GOPHERRC setup.
  1934.  
  1935. ./ ADD NAME=ABOUTCSL
  1936.  
  1937. =======================================================================
  1938.  
  1939.  Requesting Local (Serverless) Access
  1940.  
  1941. =======================================================================
  1942.  
  1943.  The LOCAL operand on the GOPHER command is a convenient way of
  1944.  requesting "local" serverless mode.  Specify LOCAL on the GOPHER
  1945.  command if you want to enter GOPHER in "serverless" mode - i.e.
  1946.  start up with your private GOPHER menu.  Specifying LOCAL
  1947.  accomplishes two things:
  1948.  
  1949.   (1) It sets the server to "-", meaning local access.  Therefore, you
  1950.       must also provide a path, either via the PATH operand on the
  1951.       GOPHER command or via a "localmenu:" spec in your GOPHERRC file,
  1952.       so that GOPHER knows where to look for your private data.  The
  1953.       path is a data set name, FULLY QUALIFIED WITHOUT QUOTES.
  1954.  
  1955.   (2) It allows you to use GOPHER even if there are other TCP/IP socket
  1956.       applications active elsewhere in your TSO session.  However, it
  1957.       will not allow you to connect to any GOPHER servers, even if you
  1958.       have a local menu item that points to one.
  1959.  
  1960.  If you do not specify a server and there is no specification in
  1961.  your GOPHERRC file for one, then GOPHER will display a startup
  1962.  ISPF panel asking you to specify a server name and, optionally,
  1963.  a path name.  (Don't touch the port number!)
  1964. ./ ADD NAME=ABOUTCSM
  1965.  
  1966. =======================================================================
  1967.  
  1968.  Defining Gopher Menus
  1969.  
  1970. =======================================================================
  1971.  
  1972.  This is a description of how to define GOPHER menus that can be used
  1973.  either for your own private data or by the GOPHER server administrator
  1974.  on MVS to define publicly accessible data.
  1975.  
  1976.  Bear in mind that the menu may be used to specify data meaningful to
  1977.  a server other than MVS.  Therefore, the descriptions here should be
  1978.  interpreted in two ways:
  1979.  
  1980.  (1) how to define MVS-resident information resources
  1981.  
  1982.  (2) how to request information resources from other GOPHER servers
  1983.  
  1984. ------------------------------------------------------------------------
  1985.  
  1986.  How To Define MVS-Resident Information Resources
  1987.  
  1988.  The Gopher server (and the Gopher client, in "local" mode) determines
  1989.  how to return information to the client via menus.  These menus are
  1990.  plain MVS data sets with a particular structure.
  1991.  
  1992.  An MVS gopher menu is a sequential data set or PDS member with the
  1993.  following format:
  1994.  
  1995.  * the first line contains the string GOPHER_MENU
  1996.    (in upper, lower or mixed case)
  1997.  
  1998.  * the rest of the file contains blocks of information like this:
  1999.  
  2000.    TYPE=type
  2001.    NAME=name
  2002.    PATH=path
  2003.    HOST=host
  2004.    PORT=port
  2005.    END
  2006.  
  2007.    For compatibility with earlier versions of the MVS Gopher server,
  2008.    the following are also accepted:
  2009.  
  2010.    DISPLAY=      is equivalent to NAME=
  2011.    SELECTOR=     is equivalent to PATH=
  2012.  
  2013.    Explanations
  2014.  
  2015.    TYPE=type
  2016.  
  2017.    The type of Gopher entity (FILE, DIRECTORY, INDEX, etc.).
  2018.    In other words, one of the following:
  2019.  
  2020.    FILE      - the item is an MVS data set with text to be displayed.
  2021.                The path name is the file name or a REXX exec spec.
  2022.    DIRECTORY - the item is another Gopher directory.
  2023.                The path name is the file name or a REXX exec spec.
  2024.    INDEX     - the item is a full text search item, which means that
  2025.                the client will query the user for a search string
  2026.                which will be passed to the server along with the
  2027.                pathname.  For the MVS server.  it only makes sense for
  2028.                the pathname to be a REXX exec specification.  The path
  2029.                and the user's string are given to the host, which
  2030.                returns a menu of selections.  See also WHOIS.
  2031.    TELNET    - the item is a Telnet server.
  2032.                The path name is ignored.  The port number should be
  2033.                omitted or set to 0, unless an alternate TELNET port
  2034.                is required by the server referenced by HOST.
  2035.    TN3270    - the item is a TN3270 server.  This is like TELNET
  2036.                except that it takes you to a full-screen IBM mainframe
  2037.                terminal session.
  2038.    CSO       - the item is a CSO phonebook server.  This is a campus
  2039.                information protocol that is not an Internet standard,
  2040.                but may be available at some universities.
  2041.    WHOIS     - the item is a "whois" query.  This is similar to the
  2042.                INDEX type, except that the server returns a file
  2043.                rather than a menu.  This is not (yet) an official
  2044.                part of the Gopher protocol, though it does appear in
  2045.                certain (patched) versions of other implementations.
  2046.    BINARY    - the item is a binary file.  Such a file may be browsed
  2047.                or copied, but it is probably of little use.
  2048.    BOOKMANAGER - the item is a BookManager READ/MVS (tm) document.
  2049.  
  2050.    NAME=name
  2051.  
  2052.    The descriptive string that will appear in the Gopher client's
  2053.    display of menu selections for this item.  Make this as human as
  2054.    possible.  Case is preserved.
  2055.  
  2056.    PATH=path
  2057.  
  2058.    The pathname to be passed to the Gopher server to retrieve the
  2059.    item.  See below for a fuller description.
  2060.  
  2061.    HOST=host
  2062.  
  2063.    The name of the Gopher server host that will process the request.
  2064.    See below for a fuller description.
  2065.  
  2066.    PORT=port
  2067.  
  2068.    The TCP/IP port to connect to.  For Gopher, this should always be
  2069.    port 70 (except for a TELNET or TN3270 type, whose port defaults to
  2070.    the standard TELNET port if zero or omitted).  If this is omitted,
  2071.    then the default port number is taken.
  2072.  
  2073.    END
  2074.  
  2075.    Formerly required to keep menu entries separate.  However, a comment
  2076.    line (any line starting with '*', '#' or '!' in the first column)
  2077.    will be interpreted as a menu entry separator, so that Gopher menu
  2078.    bookmark files may be ported from Unix systems.
  2079.  
  2080. More about Path Names
  2081.  
  2082.  Note that the format of a path depends on which Gopher server is
  2083.  going to be processing the entry, as defined by the HOST= field.
  2084.  If the entry is going to a different Gopher server, then the
  2085.  pathname format depends on that server.  For example, a Unix server
  2086.  would expect a Unix file name with a slash.
  2087.  
  2088.  In general, a selector string for an MVS Gopher server has the format:
  2089.  
  2090.    t/path
  2091.  
  2092.  where "t" is the one-character Gopher type, and "path" is usually an
  2093.  MVS data set name but may be other things, as indicated below.
  2094.  
  2095.  It may seem redundant to include the type character when the same
  2096.  information is in the TYPE= line in the menu entry.  But it really
  2097.  isn't, because the Gopher server doesn't see the TYPE= stuff when
  2098.  a client sends it a request.  The "t" character really tells the
  2099.  server what format to use when retrieving the data.  It is especially
  2100.  important when the data must be rerieved in binary rather than text
  2101.  In fact, the type does not need to match the TYPE= type.  In some
  2102.  cases it is best to specify a binary type (9) in the selector string
  2103.  along with some other kind of type.
  2104.  
  2105.  If the selector string does not begin with a type character followed
  2106.  by a slash, then the MVS gopher server will make a best guess as to
  2107.  what the type of the item is.  For data sets, it will look inside and
  2108.  return the data set as a Gopher menu if it is an MVS PDS or if it is
  2109.  a text file whose first line says "GOPHER_MENU".  Otherwise it will
  2110.  return it as a text file.  It will never return it as a binary file.
  2111.  
  2112.  Examples:
  2113.  
  2114.   SYS1.MACLIB(OPEN)         -  identifies a text file.
  2115.   0/SYS1.MACLIB(OPEN)       -  also identifies a text file.
  2116.   1/GOPHER.MENUS(THINGS)    -  identifies a menu.
  2117.  
  2118.  This is required if you want to serve a binary file:
  2119.  
  2120.   9/SYSB.RANDOM.BITS        -  identifies a binary file.
  2121.  
  2122.  Gopher has no other way of telling that the data must be
  2123.  transmitted in binary format.
  2124.  
  2125.  To be more specific about the path names for the MVS gopher server:
  2126.  
  2127.  * A fully qualified MVS data set name, without quotes, identifying
  2128.    a sequential text data set or PDS member.  If TYPE=FILE, this is
  2129.    text.  If TYPE=DIRECTORY, this is a gopher menu as described above.
  2130.  
  2131.  * A fully qualified MVS data set name, without quotes, identifying a
  2132.    PDS (no member).  This causes the MVS Gopher server to return a
  2133.    list of member names of the PDS in Gopher directory format.  This
  2134.    should be used only with TYPE=DIRECTORY.  Member aliases are
  2135.    included in the resulting list.
  2136.  
  2137.  * A member name enclosed in parentheses.  This is treated as
  2138.    a full PDS member.  In other words, the MVS Gopher server will use
  2139.    the name of the PDS in which the menu itself was found.
  2140.    This allows you to move PDS's full of Gopher menus around without
  2141.    having to worry about changing all the path names.  This happens
  2142.    only when the menu itself is a PDS member and the host is the
  2143.    same as the local host (MVS for the server, - for local mode).
  2144.    Specifying HOST=+ is recommended for this.
  2145.  
  2146.    Each member is treated as a Gopher FILE.  The NAME field is
  2147.    set to the member name.  If you want to do anything fancier
  2148.    than this, you will have to construct your own Gopher menu.
  2149.  
  2150.  * A string "DD:ddname" or "DD:ddname(member)", identifying a file by
  2151.    MVS ddname a la C/370.  Valid with either TYPE=FILE or
  2152.    TYPE=DIRECTORY, so the ddname can point to text or a menu.
  2153.    However, if the ddname happens to be allocated to a PDS, it does
  2154.    NOT work like a directory above - it's just illegal and will
  2155.    probably cause lossage.
  2156.  
  2157.  * A string "EXEC:execname args", which specifies the name of a
  2158.    REXX exec to be executed to return the data.  Valid with any
  2159.    and all types.  To learn more about how to make use of this
  2160.    feature, please go back to the "About This Gopher" tree and
  2161.    read up on using REXX execs with MVS Gopher.
  2162.  
  2163.    If you are using your own private GOPHER data via local access
  2164.    and you want to run REXX execs, you must have a "localexec:"
  2165.    line in your GOPHERRC file identifying your REXX exec library.
  2166.  
  2167.  * A string "FTPn:ftpstuff", which specifies a remote host, a file or
  2168.    directory to be fetched via anonymous FTP to that remote host, and
  2169.    the type of the file (n) to be returned.  This is valid with any
  2170.    Gopher type, but will be most useful with the FILE type (n = 0,
  2171.    TYPE=0); the DIRECTORY type (n = 1, TYPE=1); the BINARY type (n = 9,
  2172.    TYPE=9); the IMAGE type (n = g, TYPE=g); and possibly others.
  2173.  
  2174.  * A string "FTPVMn:ftpstuff", which is like FTPn except that the remote
  2175.    host is a VM/CMS machine running the "FAL" FTP server.
  2176.  
  2177.    For all of the above...
  2178.  
  2179.    Note that the HOST= and PORT= must still point to the MVS gopher
  2180.    server, which performs the remote FTP for you.
  2181.  
  2182.    In the PATH= field, an "FTPn:" style selector string may take one
  2183.    of the following forms:
  2184.  
  2185.      ftpn:host
  2186.      ftpn:host:path
  2187.      ftpn:host:user:path
  2188.      ftpn:host:user:pass:path
  2189.  
  2190.    If path is omitted, then path is the current directory of the remote
  2191.    anonymous FTP session.
  2192.    If user is omitted, defaults to "anonymous".
  2193.    If pass is omitted, defaults to "gopher@localhost.domain.qualifier".
  2194.  
  2195.    The syntax is defined to let path always be the last item
  2196.    just in case the path name contains a colon.
  2197.  
  2198.    For the VM variants, the directory is a minidisk specification, and
  2199.    the file is in the format minidisk/filename.filemode (no filetype).
  2200.  
  2201.    Examples:
  2202.  
  2203.    A directory type request...
  2204.  
  2205.     ftp1:boombox.micro.umn.edu:/pub/gopher/mvs
  2206.     ftpvm1:vm1.nodak.edu:powerl
  2207.  
  2208.    A file type request...
  2209.  
  2210.     ftp0:some.place.else.com:guest:guestpassword:/blah/README
  2211.     ftpvm0:vm1.nodak.edu:powerl/faq3.ann6000
  2212.  
  2213. More About Host Names
  2214.  
  2215.  You may find that some Gopher servers insist on appending the
  2216.  network's domain name to local server hostnames.  You should check
  2217.  with your network gurus to make sure that this will work with your
  2218.  TCP/IP host lookup.  The MVS server will accept hostnames either
  2219.  with or without the domain name appended - this applies to the
  2220.  specification of hostnames in the Gopher access table as well -
  2221.  but other Gopher servers may not.
  2222.  
  2223. Two special cases:
  2224.  
  2225.  A plus sign (HOST=+) means that the host is the same host as the one
  2226.  that is looking at the directory entry - i.e. the server that is
  2227.  serving up this menu.  The Gopher server simply plugs in its own host
  2228.  name at that point.  This is NOT part of the Gopher protocol, but
  2229.  merely a server hack.
  2230.  
  2231.  A minus sign (HOST=-) means that access to this item will be in
  2232.  "local" (serverless) mode.  This is recognized only by the MVS Gopher
  2233.  client.  It means that the client will do the retrieval itself,
  2234.  without asking a server to do it.  When you use this type, the port
  2235.  number must be 70.
  2236.  
  2237.  The directory-processing code, when invoked in "local mode", will
  2238.  treat HOST=+ as HOST=- since the current host is the local mode
  2239.  operation in that case.  Therefore, using HOST=+ is recommended
  2240.  so that one can port one's local GOPHER menus to the public server
  2241.  at some point.
  2242.  
  2243.  A REXX exec that generates menus dynamically can use - as a hostname,
  2244.  but not +.
  2245.  
  2246. ------------------------------------------------------------------------
  2247.  
  2248.  How To Request Information Resources From Other GOPHER Servers
  2249.  
  2250. Rather than describe the standard format of a Gopher menu here,
  2251. I recommend that you go to your nearest Unix box and type
  2252.  
  2253.   man gopherd
  2254.  
  2255. That should tell you all you need to know about Unix gopher servers.
  2256. If your gopher server is on some other kind of machine, then go find
  2257. the documentation for that machine's Gopher menus.
  2258.  
  2259. The purpose of the above exercise is primarily to determine the format
  2260. of a path name understood by a given Gopher server.  Once you know that,
  2261. you can build a Gopher menu the MVS Gopher will understand, according to
  2262. the format described in the top section.  Set the host to point to
  2263. the other Gopher server, who will interpret the other items in the menu.
  2264.  
  2265. ------------------------------------------------------------------------
  2266.  
  2267. Dynamic Generation of GOPHER Menus
  2268.  
  2269.  If you want to be able to generate a Gopher menu dynamically,
  2270.  you can do this via the REXX interface.  You also must understand
  2271.  the Gopher protocol.  A Gopher menu is really a text representation
  2272.  of the actual protocol, which goes like this:
  2273.  
  2274.  filetype -tab- name -tab- path -tab- host -tab- port
  2275.  
  2276.  where -tab- is the EBCDIC (on MVS) or ASCII (on other box) tab
  2277.  character, and filetype is a single character.  The filetypes
  2278.  supported by the MVS Gopher server are:
  2279.  
  2280.  0 - flat file
  2281.  1 - directory
  2282.  2 - CSO
  2283.  3 - error
  2284.  7 - index
  2285.  8 - TELNET
  2286.  9 - binary
  2287.  T - TN3270
  2288.  w - whois (experimental)
  2289.  i - comment (unselectable menu line)
  2290.  b - BookManager format
  2291.  
  2292.  A REXX exec that wants to generate a Gopher menu must output lines
  2293.  in this format.  For more information, go back to the Gopher tree
  2294.  for "About This Gopher" and look up information on the REXX interface.
  2295.  
  2296. ./ ADD NAME=ABOUTCSR
  2297.  
  2298. =======================================================================
  2299.  
  2300.  The GOPHERRC File
  2301.  
  2302. =======================================================================
  2303.  
  2304.  When you use the GOPHER client, you need a file called GOPHERRC
  2305.  which stores information about your use of GOPHER.  If you don't
  2306.  have one, GOPHER will create it for you.  The file initially
  2307.  contains:
  2308.  
  2309.     the initial path/name/host/port specification, which tells
  2310.     GOPHER what to display on startup.  By default this is the
  2311.     standard GOPHER server info on MVS.  However, you can add
  2312.     to your GOPHERRC a specification for local GOPHER by
  2313.     editing GOPHERRC and activating one of the following:
  2314.  
  2315.     - the other "initial:" spec which points to your own startup menu,
  2316.       overriding the one you'd get otherwise
  2317.  
  2318.     - the localmenu: and localexec: lines.
  2319.  
  2320.     - the telnet:, bookmgr: and domain: lines.
  2321.  
  2322.     localmenu: is equivalent to specifying an alternate initial:
  2323.     spec of host=- (dash) and path=localmenu_name.  When you use
  2324.     the LOCAL operand of the GOPHER command, localmenu: is what
  2325.     GOPHER looks for as the pathname if you don't provide one on
  2326.     the command.
  2327.  
  2328.     localexec: is required if you want to use your own library of
  2329.     GOPHER rexx execs.  This is valid for LOCAL access only.
  2330.  
  2331.     telnet: is required if you want to use a telnet command other
  2332.     than TELNET.  For example, UCLA's XTELNET is recommended if
  2333.     you have it (and if you don't have it, then get it).
  2334.  
  2335.     bookmgr: is required if your BookManager READ/MVS command is
  2336.     other than "BOOKMGR".  Note, however, that whatever command
  2337.     you specify must take a BOOK('data-set-name') argument.
  2338.  
  2339.     domain: is required if your installation hasn't configured
  2340.     the Gopher client to reference the correct local domain.
  2341.     This may be the case if you are using the object-code-only
  2342.     distribution, for example.  Normally when GOPHERRC is built
  2343.     upon your first use of the GOPHER client, this value should
  2344.     be set correctly.  There should never be any need to change it,
  2345.     assuming that it works properly, which you'll find out right
  2346.     away if it doesn't.
  2347.  
  2348.     Some option defaults may be stored in the GOPHERRC file;
  2349.     others are remembered in your ISPF profile.
  2350.  
  2351.     Note that bookmarks are not stored in your GOPHERRC file.
  2352.     They are stored in separate bookmark data sets, whose names
  2353.     the client user must specify.  Do not attempt to load your
  2354.     GOPHERRC file as a bookmark file!
  2355.  
  2356.     If you have a newly created GOPHERRC file, you can read the
  2357.     comments to guide you in customizing the file.
  2358.  
  2359.     You may also specify a different startup file when you invoke
  2360.     the MVS GOPHER client via the INITFILE keyword - e.g.
  2361.  
  2362.       GOPHER INITFILE(SOME.OTHER.RC)
  2363.  
  2364.     If the data set does not yet exist, it will be created.
  2365.  
  2366. ./ ADD NAME=ABOUTCSW
  2367.  
  2368. =======================================================================
  2369.  
  2370.  What Happens When You Start Up GOPHER?
  2371.  
  2372. =======================================================================
  2373.  
  2374.  What you see when you start up GOPHER depends on what you have
  2375.  specified, either on the command line or in the GOPHERRC file.
  2376.  In general, command operands override GOPHERRC specifications.
  2377.  
  2378.  GOPHER does its thing by connecting to a Gopher server somewhere
  2379.  on your network.  If you do not specify otherwise, this server is
  2380.  assumed to be MVS (the host where you are running this client).
  2381.  The default GOPHERRC file specifies this as the server.
  2382.  The startup menu you see is the one defined by the administrator
  2383.  of that server.
  2384.  
  2385.  You can request a different server or a different startup menu,
  2386.  either by modifying the GOPHERRC file or by specifying command
  2387.  operands.  The SERVER operand tells GOPHER to get a startup menu
  2388.  from a different server, and the PATH operand tells GOPHER what
  2389.  startup menu to request (the contents of the path depend on what
  2390.  server you point to and what it's looking for, but it is typically
  2391.  the name of a file on that system that contains a Gopher menu).
  2392.  
  2393.  You can also use GOPHER to access your own private data by requesting
  2394.  "local" (serverless) mode.  A server name of a single dash "-" means
  2395.  local access.  In this case, you must provide a path name so that
  2396.  GOPHER knows where to look for your data.  The path name is the name
  2397.  of a data set containing your GOPHER menu - it must be FULLY QUALIFIED
  2398.  AND WITHOUT QUOTES.  The path name can be provided either as a command
  2399.  operand or in the GOPHERRC file.
  2400. ./ ADD NAME=ABOUTR
  2401. gopher_menu
  2402.  
  2403. Type=0
  2404. Name=REXX Interface Overview
  2405. Path=(ABOUTRO)
  2406. Host=+
  2407. Port=+
  2408. End
  2409.  
  2410. Type=0
  2411. Name=Specifying Hostname and Port
  2412. Path=(ABOUTRH)
  2413. Host=+
  2414. Port=+
  2415. End
  2416.  
  2417. Type=0
  2418. Name=REXX Interface Reference
  2419. Path=(ABOUTRR)
  2420. Host=+
  2421. Port=+
  2422. End
  2423.  
  2424. ./ ADD NAME=ABOUTRH
  2425.  
  2426. =======================================================================
  2427.  
  2428. Specifying the Right Host Name
  2429.  
  2430. =======================================================================
  2431.  
  2432. Most of the time you will probably want to generate a menu item
  2433. that points back to your MVS host, not some other host.  It may
  2434. even redrive your selfsame REXX exec with new arguments.  And if
  2435. the exec was invoked in local (serverless) mode, you want the item
  2436. to get driven in the same mode, probably.
  2437.  
  2438. The question is - what's the easiest way to identify what
  2439. the "same server" is?  One way is to hardcode the server name (e.g.
  2440. "MVS.DRAPER.COM"), but this is not sufficiently general because:
  2441.  
  2442. (1) the server name or location may change
  2443. (2) you can't distribute the exec to other Gopher users
  2444. (3) it won't work the same way in "local mode"
  2445.  
  2446. So, you need a way to know what the name of your selfsame host is.
  2447. The MVS Gopher server can use HOST=+, but you can't, as that isn't
  2448. part of the Gopher protocol.  So what do you do?
  2449.  
  2450. You have the same problem with the Gopher port number.  You usually
  2451. want it to be the same as the one by which your REXX exec was invoked.
  2452.  
  2453. Use the functions ghost() and gport() to return the current host
  2454. name and port number.  So in the above code segment, you might have:
  2455.  
  2456.  parse arg myargs, gopherargs
  2457.  host = ghost(gopherargs)
  2458.  port = gport(gopherargs)
  2459.  
  2460. Note: the functions hostname() and port() are also available for
  2461. compatibility with earlier releases of the MVS Gopher.  However, ghost()
  2462. and gport() are recommended.  All of them are required to take
  2463. gopherargs as their argument, or else they may not work properly.
  2464.  
  2465. Note that a plus sign "+" will not work when creating a hostname for a
  2466. Gopher menu item.  The plus sign is a hack interpreted by the Gopher
  2467. server when it sees it on a menu.  It is *not* part of the Gopher
  2468. protocol and therefore cannot be sent over.
  2469.  
  2470. However, the minus sign "-" will work, as the Gopher client
  2471. in local mode will interpret it at the protocol level
  2472. (which DOES NOT IMPLY THAT IT IS A PART OF THE STANDARD
  2473. GOPHER PROTOCOL, PROPOSED OR OTHERWISE - THIS IS JUST A
  2474. LOCAL HACK MODIFICATION).
  2475.  
  2476. More details on the REXX interface are in the REXX Interface Reference.
  2477.  
  2478. ./ ADD NAME=ABOUTRO
  2479. =======================================================================
  2480.  
  2481. REXX Exec Interface Overview
  2482.  
  2483. =======================================================================
  2484.  
  2485. You can request the MVS Gopher server to retrieve information
  2486. dynamically by executing a REXX exec.  To request this, you define a
  2487. menu entry with a PATH= field that looks like one of these:
  2488.  
  2489. PATH=0/EXEC:execname args          (to return a "file")
  2490. PATH=1/EXEC:execname args          (to return a "menu")
  2491. PATH=7/EXEC:execname args          (to do a search and return a "menu")
  2492. PATH=EXEC:execname args            (the old style, still supported)
  2493.  
  2494. In all of the above, the REXX exec identified by "execname" is
  2495. executed, along with the arguments "args" given.  For example:
  2496.  
  2497. PATH=0/EXEC:MYEXEC ANY ARGS
  2498.  
  2499. will cause the MYEXEC exec to be executed with "ANY ARGS" as the
  2500. single argument string.
  2501.  
  2502. If the TYPE is INDEX, the search string submitted by the user will be
  2503. appended to the args separated by a blank.  The exec must be able to
  2504. deal with this.
  2505.  
  2506. REXX Execs must be in a PDS allocated to DD GGEXEC.  This ddname
  2507. needs to be present in the Gopher server's JCL.
  2508.  
  2509. Note that you do not need the /* REXX */ comment at the beginning of
  2510. REXX execs used by gopher (though it does not hurt to include it!),
  2511. because they are invoked by the IRXEXEC facility and not the standard
  2512. TSO CLIST/EXEC search.
  2513.  
  2514. You can also use the EXEC: interface from the MVS Gopher client in
  2515. "local" (serverless) mode.  For local mode, the GOPHER command will
  2516. allocate the GGEXEC file to the REXX exec library specified on the
  2517. "localexec:" line in your GOPHERRC file, if you have activated it.
  2518. Otherwise you will not be able to use REXX execs in local mode.
  2519.  
  2520. Now, how does the REXX exec return data to the Gopher server?
  2521.  
  2522. First of all, it depends on the TYPE that the exec is expected
  2523. to return, which has nothing to do with HOW the returning is done.
  2524.  
  2525. Second of all, it does it using various internal interfaces which
  2526. you don't have to know about or understand.  Some REXX functions
  2527. have already been provided for you to use that will do the dirty
  2528. work for you.
  2529.  
  2530. So, first let's talk about how the exec returns data, and then
  2531. about what it is expected to return.
  2532.  
  2533. How to return data
  2534.  
  2535. The REXX exec must return data by writing it to the data stack
  2536. between a call to GOPEN and a call to GCLOSE.
  2537.  
  2538. Example:
  2539.  
  2540.  parse arg myargs, gopherargs
  2541.  call gopen gopherargs
  2542.  do while more_data_to_get
  2543.   some_data = get_some_data()
  2544.   if some_data = "" then queue " "
  2545.   else queue some_data
  2546.  end
  2547.  call gclose gopherargs
  2548.  
  2549. Note:  It is recommended that you not queue any null lines.
  2550. Although this will not result in failure, the null lines are
  2551. likely to disappear for reasons I would rather not go into here.
  2552.  
  2553. If the gopher server is run straight batch rather than as a TSO job, then
  2554. you cannot run REXX execs that require a TSO environment.
  2555.  
  2556. If the Gopher server is a TSO-in-batch job (i.e. EXEC PGM=IKJEFT01),
  2557. then you can issue TSO commands from the exec.  To get the output,
  2558. though, you need to use OUTTRAP around them.  The GTSOTRAP routine is
  2559. provided to do this for you.  If the command issues TPUTs instead of
  2560. PUTLINEs, though, you are out of luck.
  2561.  
  2562. Note that a Gopher server running in TSO mode will almost certainly be a
  2563. single-threading server, to prevent more than one client from running in
  2564. the same TSO environment at the same time.
  2565.  
  2566. If you want to run a PL/1 program that writes to SYSPRINT, or a FORTRAN
  2567. or assembler program, etc., you can allocate the SYSPRINT or FT06F001
  2568. or whatever file to a temporary and dump the temporary to the stack.
  2569. The problem with both PL/1 and FORTRAN programs is that, like TSO
  2570. commands, they must be run in a single-threading Gopher server, because
  2571. otherwise you may run into a conflict if two clients try to write to
  2572. the same DDNAME.
  2573.  
  2574. If, on the other hand, your program is a C/370 program that writes to
  2575. stdout or stderr, you can avoid this problem by using redirection,
  2576. as in this example using a C program called HELLO:
  2577.  
  2578.  for stdout:
  2579.  
  2580.    stdout = grabtemp()
  2581.    call gcall "HELLO", args "> DD:"stdout
  2582.    call gopen gopherargs
  2583.    "EXECIO * DISKR" stdout "(FINIS)"
  2584.    call ungrab stdout
  2585.    call gclose gopherargs
  2586.  
  2587.  for stderr:
  2588.  
  2589.    stderr = grabtemp()
  2590.    call gcall "HELLO", args "2> DD:"stderr
  2591.    call gopen gopherargs
  2592.    "EXECIO * DISKR" stderr "(FINIS)"
  2593.    call ungrab stderr
  2594.    call gclose gopherargs
  2595.  
  2596.  For multiple output, use >> instead of > in your parameter list.
  2597.  
  2598.  Note that the C program must reside in a library allocated to
  2599.  STEPLIB in the gopher server JCL.  Of course, you can use the TSO
  2600.  CALL command if you're using the single-threaded TSO server, but
  2601.  then you wouldn't be worrying about this issue anyway.
  2602.  
  2603.  Recommended JCL for executing the Gopher server may be found
  2604.  elsewhere in the installation materials, or your MVS system
  2605.  programmer has probably already installed a Gopher server or two in
  2606.  'SYS1.PROCLIB' or the equivalent with the correct allocation.
  2607.  
  2608. What it is expected to return
  2609.  
  2610.  OK - now the good stuff.  This depends on the TYPE on the menu entry
  2611.  that your exec is trying to fulfill.  Some gopher protocol basics:
  2612.  
  2613.  A Gopher menu is really a text representation of the actual protocol,
  2614.  which goes like this:
  2615.  
  2616.  filetype name -tab- path -tab- host -tab- port
  2617.  
  2618.  where -tab- is the EBCDIC (on MVS) or ASCII (on other box) tab
  2619.  character, and filetype is a single character.  The filetypes
  2620.  supported by the MVS Gopher server include:
  2621.  
  2622.  0 - flat file
  2623.  1 - directory
  2624.  7 - index
  2625.  
  2626.  There are also other types, including binary types, but you won't be
  2627.  able to use those with REXX execs, at least not now.
  2628.  
  2629.  To generate the equivalent of a Gopher menu, you must output data
  2630.  in the above format.  Now for the details...
  2631.  
  2632. TYPE=FILE
  2633.  
  2634. Just return the straight data.  Try to avoid null lines because C/370
  2635. believes they don't exist and will throw them away.  Change all null
  2636. lines to lines containing one blank as you write them out (you're used
  2637. to doing this if you are queueing output on the stack) and you will
  2638. have no problems.
  2639.  
  2640. TYPE=DIRECTORY
  2641.  
  2642. You must return lines that fit the gopher protocol format as above.
  2643.  
  2644. For example, if you want to generate a Gopher menu on the fly that
  2645. is equivalent to this:
  2646.  
  2647.  type=file
  2648.  name=This is my description
  2649.  path=some.gopher.path
  2650.  host=sun1.sanjuan.com
  2651.  port=70
  2652.  
  2653. then you output a line that looks like this:
  2654.  
  2655.   0This is my description!some.gopher.path!sun1.sanjuan.com!70
  2656.  
  2657. (each ! is really a tab (EBCDIC hex 05) character)
  2658.  
  2659. where "0" is the type (file in this example, but would be "1" for
  2660. type=directory, "7" for typeindex, etc.)
  2661.  
  2662. Here's the REXX code that might do this:
  2663.  
  2664.  name = "This is my description"
  2665.  path = "some.gopher.path"
  2666.  host = "sun1.sanjuan.com"
  2667.  port = 70
  2668.  tab  = '05'x
  2669.  queue "0"||name||tab||path||tab||host||tab||port
  2670.  
  2671. See "Specifying Hostname and Port" for more information.
  2672.  
  2673. ./ ADD NAME=ABOUTRR
  2674.         MVS Gopher (Version 3) - New REXX Interface
  2675.  
  2676. The REXX interface for the MVS gopher server has been completely
  2677. rewritten.  Features:
  2678.  
  2679.         It is much easier to write REXX execs that work without
  2680.         needing arcane facilities.
  2681.  
  2682.         The right hostname and port are automatically taken care of.
  2683.  
  2684.         Execs do not require a TSO environment, so they can be run
  2685.         from a truly multitasking non-TSO Gopher server.
  2686.  
  2687. Here is how it works.
  2688.  
  2689. A REXX exec is invoked from a Gopher menu option by defining a
  2690. Gopher menu item something like this:
  2691.  
  2692.         Type=t (whatever type)
  2693.         Name=the name of your option
  2694.         Path=n/EXEC:execname parameters
  2695.         Host=mvs.draper.com
  2696.         Port=pn
  2697.  
  2698. where:
  2699.  
  2700.         t is the type to be asked for by the client
  2701.         (0 = text, 1 = menu, 7 =- index, etc.).
  2702.  
  2703.         n is the type to be returned by the exec
  2704.         (0 = text, 1 = menu, 9 = binary, etc.).
  2705.         Usually (but not always) this will match "t".
  2706.  
  2707.         pn is the port number (70 for the primary gopher server,
  2708.         1570 for the secondary, if you follow the recommended
  2709.         conventions for two gopher servers).
  2710.  
  2711.         execname is the name of the exec (1-8 characters).  It
  2712.         must be a member of the PDS allocated to DDname GGEXEC
  2713.         in the gopher server started task JCL.
  2714.  
  2715.         parameters are arguments, if any, passed to the exec.
  2716.  
  2717. For the path name, the n/ part may be omitted for compatibility
  2718. with the old style of REXX exec invocation.  The purpose of the
  2719. n/ part is to identify the type:  0/ means return text data,
  2720. 1/ means return a menu, 9/ means return binary data, etc.
  2721. If this is omitted, text data is assumed - of course, if the
  2722. gopher client originally asked for a menu, then the output will
  2723. be assumed to be in gopher menu format.
  2724.  
  2725. The REXX exec itself will work like this:
  2726.  
  2727. It takes two argument values, which can be parsed thusly:
  2728.  
  2729.  parse arg rexxargs, gopherargs
  2730.  
  2731. "rexxargs" is whatever follows "EXEC:execname" in the
  2732. menu item.  For type 7 (index), the search string that the
  2733. client user typed in gets appended to the value in the path,
  2734. separated by a space.
  2735.  
  2736. "gopherargs" is a string that contains information needed by
  2737. the exec to communicate with Gopher.  You don't need to know
  2738. the format of this, since all you will do is pass it to a
  2739. series of REXX functions that are provided as part of the
  2740. Gopher - REXX interface.  These functions must be stored in
  2741. the DDname GGEXEC PDS (you can use concatenated PDS's if you
  2742. like).  These functions are:
  2743.  
  2744.         GCALL
  2745.         GCLOSE
  2746.         GHOST
  2747.         GNOTIFY
  2748.         GOPEN
  2749.         GPORT
  2750.         GRAB
  2751.         GRABTEMP
  2752.         GREAD
  2753.         GTSOTRAP
  2754.         UNGRAB
  2755.  
  2756. For compatibility with the instructions given in previous
  2757. versions of the MVS gopher, the following functions are
  2758. also provided:
  2759.  
  2760.         HOSTNAME                (obsolete, use GHOST)
  2761.         PORT                    (obsolete, use GPORT)
  2762.  
  2763. However, they now take a gopherargs argument:
  2764.  
  2765.         hostname(gopherargs)
  2766.         port(gopherargs)
  2767.  
  2768. Installation note:  You must be running at least TSO/E 2.3.1
  2769. to use GCALL, and you need to install the XGALLOC program
  2770. in a library allocated to STEPLIB in the gopher server
  2771. started task JCL - this is used by GRAB, GRABTEMP and UNGRAB.
  2772.  
  2773. If you cannot use one or more of GCALL or the GRAB family,
  2774. you can still run the REXX interface, but you must use the
  2775. TSO "ALLOCATE", "FREE" and "CALL" commands.  That means you
  2776. must run a server that runs IKJEFT01 and single-threads.
  2777.  
  2778. GREAD and GTSOTRAP are merely conveniences for the programmer.
  2779. Note that GTSOTRAP by its nature, unlike the others, actually
  2780. requires a TSO environment to be present.
  2781.  
  2782. Explanation:
  2783.  
  2784.         GCALL    - call a compiled (assembler, C, etc.) program
  2785.         GCLOSE   - write out and close GOPHER text output stream
  2786.         GHOST    - return the hostname of the current menu item
  2787.         GNOTIFY  - log a write-to-programmer message to syslog
  2788.         GOPEN    - open GOPHER text output stream
  2789.         GRAB     - allocate an existing data set
  2790.         GRABTEMP - allocate a temporary data set
  2791.         GREAD    - read contents of a file onto the stack
  2792.         GTSOTRAP - direct output of a TSO command onto the stack
  2793.         UNGRAB   - unallocate a file
  2794.  
  2795. Note the routines that write stuff onto the stack, and also the
  2796. fact that there is no "GWRITE" routine.  Why?  Because the way to
  2797. send Gopher data remains the same as it was in earlier versions:
  2798. you queue it onto the REXX data stack.  The difference is that
  2799. you call the GOPEN and GCLOSE routines to manage the stack - you
  2800. do not need to fool around with EXECIO or SYSTSPRT.  In fact,
  2801. SYSTSPRT is not even used anymore.
  2802.  
  2803. Many of these functions take gopherargs as an argument, because
  2804. gopherargs contains the information they need to function.
  2805.  
  2806. Why the funny routines?
  2807.  
  2808. Well, for one thing, to make it easier for you to write your REXX
  2809. code.  But also to enforce certain things.  When you are working in a
  2810. multitasking environment, there are some things that you may be used to
  2811. doing that you cannot do.  Chief among them is that you cannot use
  2812. hardcoded or preset ddnames.  There may be several gopher execs running
  2813. simultaneously and your execs can blow each other (and gopher) away if
  2814. you do.  That is why we provide allocation routines - they generate
  2815. unique ddnames and return them to your exec, and you are supposed to
  2816. use those ddnames and no other.
  2817.  
  2818. Also, this frees you from the necessity of having a TSO environment,
  2819. where you cannot use commands like ALLOCATE.
  2820.  
  2821. Detailed Descriptions
  2822.  
  2823. GCALL    - call a compiled (assembler, C, etc.) program
  2824.  
  2825. Syntax:  call gcall modulename, parameters
  2826.  
  2827. Returns: the return code from the specified module
  2828.          in REXX variable "RESULT" (as per the REXX "call" statement)
  2829.  
  2830. Example:  call gcall "IEFBR14", "SIZE=200K"
  2831.           say "Return code is" result
  2832.  
  2833. GCLOSE   - write out and close GOPHER text output stream
  2834.  
  2835. Syntax:    call gclose gopherargs
  2836.  
  2837. Returns:   nothing of interest
  2838.  
  2839. Example:   parse arg foo bar baz , gopherargs
  2840.            call gopen gopherargs
  2841.            queue "This is some Gopher data."
  2842.            queue "This is some more Gopher data."
  2843.            call gclose gopherargs
  2844.  
  2845. GHOST    - return the hostname of the current menu item
  2846.  
  2847. Syntax:    host = ghost(gopherargs)
  2848.  
  2849. Returns:   the hostname of the MVS gopher server that invoked you
  2850.  
  2851. Example:   parse arg foo bar baz , gopherargs
  2852.            tab = x'05'
  2853.            type = "0"
  2854.            name = "Cool Stuff"
  2855.            path = "0/EXEC:KOOLS" foo
  2856.            host = ghost(gopherargs)
  2857.            port = gport(gopherargs)
  2858.            queue  type || name || tab || path || tab || host || tab || port
  2859.  
  2860. GNOTIFY  - send a write-to-programmer log message to the system log
  2861.  
  2862. Syntax:    call gnotify "GGMVSnnn message text"
  2863.  
  2864. Returns:   nothing
  2865.  
  2866. Comments:  If you have disabled logging in the server, you probably don't
  2867.            want to be using this either.
  2868.  
  2869. Example:   call gnotify ,
  2870.             "GGMVS999 The Gopher server is experiencing grave lossage."
  2871.  
  2872. GOPEN    - open GOPHER text output stream
  2873.  
  2874. Syntax:    call gopen gopherargs
  2875.  
  2876. Returns:   nothing of interest
  2877.  
  2878. Example:   parse arg foo bar baz , gopherargs
  2879.            call gopen gopherargs
  2880.            queue "This is some Gopher data."
  2881.            queue "This is some more Gopher data."
  2882.            call gclose gopherargs
  2883.  
  2884. GRAB     - allocate an existing data set
  2885.  
  2886. Syntax:    newddname = grab(datasetname,disposition)
  2887.            datasetname is a fully qualified MVS name (quotes optional)
  2888.            disposition is one of: SHR OLD MOD NEW
  2889.  
  2890. Returns:   a unique ddname (null string if allocation failed)
  2891.  
  2892. Comments:  GRAB stands for "Gopher Resource Allocation in Batch"
  2893.  
  2894. Example:   infodd = grab("GOPHER.INFO.DATA","SHR")
  2895.            if infodd = "" then exit 12 /* fail */
  2896.            call gopen gopherargs
  2897.            call gread infodd
  2898.            call gclose gopherargs
  2899.            call ungrab infodd
  2900.  
  2901. GRABTEMP - allocate a temporary data set
  2902.  
  2903. Syntax:    newddname = grabtemp()
  2904.  
  2905. Returns:   a unique ddname (null string if allocation failed)
  2906.  
  2907. Comments:  GRABTEMP stands for "Gopher Resource Allocator in Batch to
  2908.            Touch Empty Memory Pages"
  2909.  
  2910. Example:   tempdd = grabtemp()
  2911.            if tempdd = "" then exit 12 /* fail */
  2912.            "newstack"
  2913.            queue "hi there"
  2914.            queue "bye"
  2915.            queue ""
  2916.            "EXECIO * DISKW" tempdd "(FINIS)"
  2917.            call ungrab tempdd
  2918.  
  2919. GREAD    - read contents of a file onto the stack
  2920.  
  2921. Syntax:    call gread ddname
  2922.  
  2923. Returns:   nothing of interest
  2924.  
  2925. Comments:  ddname should have been set by call to GRAB or GRABTEMP first
  2926.  
  2927. Example:   infodd = grab("GOPHER.INFO.DATA","SHR")
  2928.            if infodd = "" then exit 12 /* fail */
  2929.            call gopen gopherargs
  2930.            call gread infodd
  2931.            call gclose gopherargs
  2932.            call ungrab infodd
  2933.  
  2934. GTSOTRAP - direct output of a TSO command onto the stack
  2935.  
  2936. Syntax:    call gtsotrap tsocommandstring, gopherargs
  2937.  
  2938. Returns:   the return code from the TSO command
  2939.  
  2940. Comments:  TSO environment is required.  Note that thisn routine
  2941.            does gopen and gclose internally.  DO NOT CALL GOPEN
  2942.            OR GCLOSE IF YOU USE THIS ROUTINE.
  2943.  
  2944. Example:   parse arg stuff, gopherargs
  2945.            call gtsotrap "LISTD" stuff "M ST", gopherargs
  2946.  
  2947. UNGRAB   - unallocate a file
  2948.  
  2949. Syntax:    call ungrab ddname
  2950.  
  2951. Returns:   return code from dynamic unallocation
  2952.  
  2953. Example:   infodd = grab("GOPHER.INFO.DATA","SHR")
  2954.            if infodd = "" then exit 12 /* fail */
  2955.            call gopen gopherargs
  2956.            call gread infodd
  2957.            call gclose gopherargs
  2958.            call ungrab infodd
  2959.  
  2960. An Example for You to Play With
  2961.  
  2962. This "REXXTEST" gopher menu item allows you to poke around and
  2963. see what is really going on in the REXX world  Try it.
  2964.  
  2965. TYPE=0
  2966. NAME=Test the REXX Interface on port 70 (MVS Gopher server 1)
  2967. PATH=EXEC:REXXTEST
  2968. HOST=+
  2969. PORT=70
  2970. END
  2971.  
  2972. TYPE=0
  2973. NAME=Test the REXX Interface on port 1570 (MVS Gopher server 2)
  2974. PATH=EXEC:REXXTEST
  2975. HOST=+
  2976. PORT=1570
  2977. END
  2978.  
  2979. and here is the REXXTEST exec:
  2980.  
  2981. /* REXX */
  2982.  
  2983. parse arg args, gopherargs
  2984. parse version rexx_version
  2985. parse source rexx_source
  2986.  
  2987. call gopen gopherargs
  2988.  
  2989. queue "PARSE VERSION returns:" rexx_version
  2990. queue "PARSE SOURCE  returns:" rexx_source
  2991. queue "Argument 1 is........." args
  2992. queue "Gopherargs are........" gopherargs
  2993.  
  2994. call gclose gopherargs
  2995.  
  2996. return
  2997.  
  2998. ./ ADD NAME=ABOUTS
  2999. gopher_menu
  3000.  
  3001. TYPE=FILE
  3002. NAME=Creating MVS Gopher Menus
  3003. PATH=(ABOUTCSM)
  3004. HOST=+
  3005. END
  3006.  
  3007. TYPE=FILE
  3008. NAME=MVS Gopher Access Table
  3009. PATH=(ABOUTSA)
  3010. HOST=+
  3011. END
  3012.  
  3013. TYPE=FILE
  3014. NAME=MVS Gopher Startup Parameters
  3015. PATH=(ABOUTSP)
  3016. HOST=+
  3017. END
  3018.  
  3019. TYPE=DIRECTORY
  3020. NAME=REXX Exec Interface
  3021. PATH=(ABOUTR)
  3022. HOST=+
  3023. END
  3024.  
  3025. ./ ADD NAME=ABOUTSA
  3026.  
  3027.           Format of entries in the Gopher Access Table
  3028.  
  3029.   Each entry in the table is a single line containing, in the most
  3030.   general sense, a filename followed by a list of hostnames.
  3031.  
  3032.   The filename (fully qualified, all uppercase, no quotes)
  3033.   can be a fully qualified MVS data set name, or a string like
  3034.   DD:DDNAME or EXEC:EXECNAME.  It can also contain an asterisk
  3035.   for a wildcard specification - see below for more details.
  3036.  
  3037.   The hostnames are names of TCP/IP machines which are authorized to
  3038.   access the data.  If no host name list is present, all hosts are
  3039.   authorized to access the specified filename.
  3040.  
  3041.   You may specify the same file name more than once, if you need more
  3042.   lines to put additional host names on.  There is no syntactic
  3043.   convention for continuing a long line, so this is how you would do
  3044.   it.  This allows multiple entries for a path specifying different
  3045.   hosts, so the MVS administrator doesn't have to worry about running
  3046.   out of room on a line.
  3047.  
  3048.   Individual PDS members are specified separately.  A PDS without
  3049.   a member name establishes access only to the PDS directory.
  3050.   However, you can use wildcarding to specify access to all members
  3051.   of a given PDS:  just put an asterisk in place of the member name.
  3052.   For example, SYS1.SOME.PDS(*) would define access to all members
  3053.   of SYS1.SOME.PDS.
  3054.  
  3055.   Note that the default directory (DD:GGGOPHER) MUST be in this table.
  3056.   You could use this entry to define access to the top-level server.
  3057.  
  3058.   Also note that in the case of EXECs, the EXEC must live in the
  3059.   library allocated to GGEXEC in the Gopher server JCL.  (Of course;
  3060.   how could it be executed otherwise?)
  3061.  
  3062.   *** ANY DATA SET REFERENCED BY ANY EXEC IN THAT LIBRARY, AS WELL AS
  3063.   *** ANY EXEC INVOKED BY THE FIRST EXEC, IS FULLY ACCESSIBLE TO GOPHER
  3064.   *** REGARDLESS OF THIS TABLE!  USE THIS TABLE TO GOVERN CONTROL TO
  3065.   *** THE EXEC ITSELF!!!
  3066.  
  3067. How Wildcards Are Handled
  3068.  
  3069. In prior versions of MVS Gopher, the access file was read each time a
  3070. client request came in and the format was limited to:
  3071.  
  3072.  dsname        host1 host2 host3
  3073.  
  3074. The file was read until an entry that matched both the path and the
  3075. host was found.  If no such entry existed the access was denied.  Doing
  3076. it this way also allowed for multiple entries for a path specifying
  3077. different hosts, so the MVS administrator didn't have to worry about
  3078. running out of room on a line.
  3079.  
  3080. In V3, the access file contains lines that are read into memory and
  3081. sorted into an appropriate order.  The format is:
  3082.  
  3083.  pathspec     hostspec1 hostspec2 hostspec3
  3084.  
  3085. "pathspec" may be a wildcard expression.  Currently, the only wildcard
  3086. syntax is a single asterisk ("*" character) somewhere in the pathspec.
  3087.  
  3088.  "hostspecn" is a hostname, as before.
  3089.  
  3090. Access Rule Prioritization
  3091.  
  3092. Since with wildcards, a path can match more than one rule, with possible
  3093. conflicting results, an algorithm has been established for picking the
  3094. appropriate access rule.
  3095.  
  3096. Each rule is given two weight values - a major weight and a minor
  3097. weight.  You can see these weights printed out by the server when the
  3098. server is started up.
  3099.  
  3100. The major weight is set to the actual length of the pathname in
  3101. characters, excepting wildcard characters.  This represents the number
  3102. of explicit characters in the pathspec that matches the target name.
  3103. The minor weight is set to the number of characters preceding the
  3104. asterisk (the entire length of the path if no wildcard).  The rules are
  3105. then sorted in descending order of major and minor weight.  We will
  3106. refer to this major and minor weight as a "weight-pair".
  3107.  
  3108. When a client request comes in, a search is done until a rule is found
  3109. that matches the path - in other words, the highest weight-pair
  3110. associated with a matching rule is found.  Then, all the rules with the
  3111. same weight-pair as that rule are tested.  If the request matches ANY
  3112. of these rules and succeeds (i.e. one of these rules has both a
  3113. maatching path and a matching host), the access is allowed.  If the
  3114. request does not match any of these rules, the access is denied - no
  3115. rules of other weight-pairs are checked.
  3116.  
  3117. Consider this example:
  3118.  
  3119.  foo.bar.baz  host0
  3120.  foo.*.baz    host1 host2 host3
  3121.  foo.bar.*    host4 host5 host6
  3122.  foo.*        host7 host8 host9
  3123.  *.baz        host10 host11 host12
  3124.  foo.xxx.*    host13 host14 host15
  3125.  
  3126. The above rules have the following weights:
  3127.  
  3128.  Pathname     Major  Minor
  3129.  
  3130.  foo.bar.baz   11     11
  3131.  foo.bar.*      8      8
  3132.  foo.xxx.*      8      8
  3133.  foo.*.baz      8      4
  3134.  foo.*          4      4
  3135.  *.baz          4      0
  3136.  
  3137. We've displayed the rules above in the order in which they will be
  3138. searched.  They could have been specified in any order in the
  3139. access file.  The only time the order in the access file matters
  3140. is for rules of the same weight-pair.
  3141.  
  3142. Now, if a client requests to see a file, here's what happens.
  3143.  
  3144. If the request is for file foo.bar.baz, the first rule, with weight-pair
  3145. 11-11, matches.  This is the obvious case where we have an exact match
  3146. with no wildcards, which always is "best".
  3147.  
  3148. So, the only host that can access foo.bar.baz is host0, because there
  3149. is an explicit rule governing it, the "foo.bar.baz" rule, which "wins".
  3150.  
  3151. If, on the other hand, the request is for file foo.bar.mumble.baz, all
  3152. except two of the rules apply.  "foo.bar.baz" and "foo.xxx.*" do not
  3153. match, but all the other rules do in this case.  However, only the
  3154. rules of the "best" weight-pair will apply.  Here the highest
  3155. weight-pair among the eligible rules is 8-8, because we have a pathname
  3156. match with "foo.bar.*".  Therefore, only rules of weight-pair 8-8 will
  3157. be considered.  Since the only rule of weight-pair 8-8 that matches the
  3158. client's requested file name is the "foo.bar.*" rule, the only hosts
  3159. that can access this file are host4, host5, and host6.
  3160.  
  3161. Looking at it another way, "foo.bar.*" is a "better" match than
  3162. "foo.*.baz", "foo.*" or "*.baz", even though they all potentially
  3163. match, so we apply the "foo.bar.*" rule and do whatever it says.
  3164.  
  3165. Now, consider a request for foo.bar.mumble.  That could match any of
  3166. "foo.bar.*" or "foo.*" - but, as we have seen, "foo.bar.*" is a more
  3167. powerful match, as proven by its weight-pair.  Therefore,
  3168. foo.bar.mumble can be accessed by host4, host5 and host6.  Note that
  3169. host7, host8 and host9 cannot access it, even though it would seem to
  3170. match the "foo.*" rule, because the "foo.bar.*" rule takes precedence.
  3171.  
  3172. In cases where more than one rule with a given weight-pair should
  3173. match a given file, the first one that finds a matching host wins,
  3174. as with Gopher v2.  This allows you to continue to specify the same
  3175. file name with multiple host strings.
  3176.  
  3177. ./ ADD NAME=ABOUTSP
  3178.  
  3179.  MVS Gopher Startup Parameter File
  3180.  
  3181.  The Gopher server started task may contain a DD statement pointing
  3182.  to DDname GGPARMS.  If so, this file contains startup parameters
  3183.  for that invocation of the server.  If such a file does not exist,
  3184.  the defaults (as in the header file GGUSER) are used.
  3185.  
  3186.  One possible use of this feature is to have more than one MVS Gopher
  3187.  server running, with different port numbers.  This may prevent some
  3188.  bottlenecking situations.
  3189.  
  3190.  All entries in this file have the format:   variable value comments
  3191.  
  3192.  These are the possible values and their default settings:
  3193.  
  3194.  mtftasks 1    Number of concurrent subtasks to handle client requests
  3195.  port     70   The TCP port number by which clients connect
  3196.  qlength  20   Queue length for TCP server listen function
  3197.  timeout  60   Connection timeout specified when socket is closed
  3198.  domain   .DRAPER.COM     The suffix to be appende to bald host names
  3199.  
  3200. You may notice that the TELNET command may be set in this file too.
  3201. That was probably a misunderstanding, as it's the client, not the
  3202. server, that controls how telnets are to be done.
  3203.  
  3204. ./ ADD NAME=ABOUTW
  3205. What is Gopher?
  3206.  
  3207. For more information, read the FAQ, posted to USENET newsgroups
  3208. comp.infosystems.gopher and news.answers every two weeks.
  3209.  
  3210. The information contained here is borrowed therefrom in large part.
  3211.  
  3212. Gopher is a client/server protocol for building a distributed
  3213. information delivery service.  While providing a delivery vehicle for
  3214. local information, Gopher also facilitates access to other Gopher and
  3215. information servers on the Internet.
  3216.  
  3217. Gopher servers and clients can be obtained via anonymous ftp to
  3218. boombox.micro.umn.edu.  Look in the directory /pub/gopher.
  3219.  
  3220.      There are clients for the following systems.  For the latest
  3221.      directory information, see the FAQ.
  3222.  
  3223.       Unix Curses & Emacs
  3224.       Xwindows
  3225.       Macintosh Hypercard
  3226.       Macintosh Application
  3227.       DOS w/Clarkson Driver
  3228.       NeXTstep
  3229.       VM/CMS
  3230.       VMS
  3231.       MVS
  3232.  
  3233.      There are also a number of public telnet login sites available.
  3234.      See the FAQ for more information.
  3235.  
  3236.      There are servers for the following systems.  For the latest
  3237.      directory information, see the FAQ.
  3238.  
  3239.        Unix
  3240.        VMS
  3241.        Macintosh
  3242.        VM/CMS
  3243.        MVS
  3244.  
  3245.  
  3246. Papers and articles describing Gopher:
  3247.  
  3248.      _The_Internet_Gopher_, "ConneXions", July 1992, Interop.
  3249.  
  3250.      _Exploring_Internet_GopherSpace_ "The Internet Society News", v1n2 1992,
  3251.  
  3252.      _The_Internet_Gopher_Protocol_, Proceedings of the Twenty-Third
  3253.           IETF, CNRI, Section 5.3
  3254.  
  3255.      _Internet_Gopher_, Proceedings of Canadian Networking '92
  3256.  
  3257.      _The_Internet_Gopher_, INTERNET: Getting Started, SRI
  3258.           International, Section 10.5.5
  3259.  
  3260.      _Tools_help_Internet_users_discover_on-line_treasures, Computerworld,
  3261.           July 20, 1992
  3262.  
  3263.      Gopher will also be in two forthcoming O'Reilly Books:
  3264.      "Administrating TCP/IP, and The Whole Internet"
  3265.  
  3266. ./ ADD NAME=FAQ
  3267. From: gopher@boombox.micro.umn.edu (UofMN Gopher Team)
  3268. Subject: Gopher (comp.infosystems.gopher) Frequently Asked Questions (FAQ)
  3269. Summary: Common Questions and Answers about the Internet Gopher, a
  3270.         client/server protocol for making a world wide information
  3271.         service, with many implementations.
  3272. Organization: University of Minnesota, Twin Cities
  3273. Date: Thu, 23 Sep 1993 14:58:54 GMT
  3274.  
  3275. Archive-name: gopher-faq
  3276. Last-modified: 1993/08/16
  3277.  
  3278. Common Questions and Answers about the Internet Gopher, a
  3279. client/server protocol for making a world wide information service,
  3280. with many implementations.  Posted to comp.infosystems.gopher,
  3281. comp.answers, and news.answers every two weeks.
  3282.  
  3283. The most recent version of this FAQ can be gotten through gopher, or
  3284. via anonymous ftp:
  3285.  
  3286. rtfm.mit.edu:/pub/usenet/news.answers/gopher-faq
  3287.  
  3288. Those without FTP access should send e-mail to mail-server@rtfm.mit.edu
  3289. with "send usenet/news.answers/finding-sources" in the body to find out
  3290. how to do FTP by e-mail.
  3291.  
  3292. -------------------------------------------------------------------
  3293. List of questions in the Gopher FAQ:
  3294.  
  3295. Q0:  What is Gopher?
  3296. Q1:  Where can I get Gopher software?
  3297. Q2:  What do I need to access Gopher?
  3298. Q3:  Where are there publicly available logins for Gopher?
  3299. Q4:  How can I add to the information in gopher?
  3300. Q5:  Who Develops Gopher Software?
  3301. Q6:  How can I set up a "CSO" phone book server?  Where is the software?
  3302. Q7:  Why can't I access the University of Minnesota's UPI news?
  3303. Q9:  What are the type characters for the different Gopher Objects?
  3304. Q10: When I do full-text searches I always get every document back, Why?
  3305. Q11: When I try to build the UNIX software I get an error from make:
  3306.      "Must be a separator on rules line #. Stop"  Why?
  3307. Q12: What is the relationship between Gopher and (WAIS, WWW, ftp)?
  3308. Q13: Are papers or articles describing Gopher available?
  3309. Q14: On a DECstation I get the error message "/etc/svc.conf no such file
  3310.      or directory" when running the gopherd server, why?
  3311. Q15: The boolean searching terms don't work for my full-text index, why?
  3312. Q16: When linking the Unix gopher server with WAIS I get undefined symbols,
  3313. Q18: Why don't my WAIS indexes work?  I never get anything back for searches.
  3314.      or Why do I get "Dangling file" error messages in my logfile?
  3315. Q19: My gopher server doesn't work under inetd, why?
  3316. Q20: This is not a bug report, just a curiosity. I managed to install
  3317. Q21: Help!  I have PC-NFS and want to use the PC-Gopher client.  How?
  3318. Q22: How do I nuke a hung TCP connection?  I can't restart my UNIX
  3319.      gopher server unless I get rid of it, and I don't want to reboot!
  3320. Q23: Is there somewhere I can retrieve a list of announced gopher
  3321.      links?  I'd like to keep a local, up-to-date list of available gopher
  3322.      holes without requiring our users to gopher to umn just to scan
  3323.      GopherSpace.
  3324. Q24: Why doesn't my unix gopher client display ISO-Latin-1 characters
  3325. Q25: What is veronica?
  3326. Q26: What e-mail/usenet discussions lists are active for Gopher?
  3327. Q27: How do I get my Gopher (whois/cso/library catalog) listed in gopher menus?
  3328. Q28: Where is the registered list of gopher+ view types?
  3329.  
  3330. -------------------------------------------------------------------
  3331. Q0:  What is Gopher?
  3332.  
  3333. A0:  The Internet Gopher client/server provides a distributed
  3334.      information delivery system around which a world/campus-wide
  3335.      information system (CWIS) can readily be constructed.   While
  3336.      providing a delivery vehicle for local information,  Gopher
  3337.      facilitates access to other Gopher and information servers
  3338.      throughout the world.
  3339.  
  3340. -------------------------------------------------------------------
  3341. Q1:  Where can I get Gopher software?
  3342.  
  3343. A1:  via anonymous ftp to boombox.micro.umn.edu.  Look in the directory
  3344.      /pub/gopher
  3345.  
  3346. --------------------------------------------------------------------
  3347. Q2:  What do I need to access Gopher?
  3348.  
  3349. A2:  You will need a gopher "client" program that runs on your local PC
  3350.      or workstation
  3351.  
  3352.      There are clients for the following systems.  The directory
  3353.      following the name is the location of the client on the anonymous
  3354.      ftp site boombox.micro.umn.edu (134.84.132.2) in the directory
  3355.      /pub/gopher.
  3356.  
  3357.       Unix Curses & Emacs   :  /pub/gopher/Unix/gopher+2.0.tar.Z
  3358.       Xwindows (athena)     :  /pub/gopher/Unix/xgopher.1.3.tar.Z
  3359.       Xwindows (Motif)      :  /pub/gopher/Unix/moog
  3360.       Xwindows (Xview)      :  /pub/gopher/Unix/xvgopher
  3361.       Macintosh Hypercard   :  /pub/gopher/Macintosh-TurboGopher/old-versions *
  3362.       Macintosh Application :  /pub/gopher/Macintosh-TurboGopher/ *
  3363.       DOS w/Clarkson Driver :  /pub/gopher/PC_client/
  3364.       NeXTstep              :  /pub/gopher/NeXT/
  3365.       VM/CMS                :  /pub/gopher/Rice_CMS/ or /pub/gopher/VieGOPHER/
  3366.       VMS                   :  /pub/gopher/VMS/
  3367.       OS/2 2.0              :  /pub/gopher/os2/
  3368.       MVS/XA                :  /pub/gopher/mvs/
  3369.  
  3370.      Many other clients and servers have been developed by others, the
  3371.      following is an attempt at a comprehensive list.
  3372.  
  3373.       A Microsoft Windows Winsock client "The Gopher Book"
  3374.        sunsite.unc.edu:/pub/micro/pc-stuff/ms-windows/winsock/apps/gophbook.zip
  3375.  
  3376.       A Macintosh Application, "MacGopher".
  3377.         ftp.cc.utah.edu:/pub/gopher/Macintosh *
  3378.  
  3379.       Another Macintosh application, "GopherApp".
  3380.         ftp.bio.indiana.edu:/util/gopher/gopherapp *
  3381.  
  3382.       A port of the UNIX curses client for DOS with PC/TCP
  3383.         oac.hsc.uth.tmc.edu:/public/dos/misc/dosgopher.exe
  3384.  
  3385.       A port of the UNIX curses client for PC-NFS
  3386.          bcm.tmc.edu:/nfs/gopher.exe
  3387.  
  3388.       A beta version of the PC Gopher client for Novell's LAN Workplace
  3389.       for DOS
  3390.          lennon.itn.med.umich.edu:/dos/gopher
  3391.  
  3392.       A VMS DECwindows client for use with Wollongong or UCX
  3393.          job.acs.ohio-state.edu:XGOPHER_CLIENT.SHARE
  3394.  
  3395.  
  3396.      * Note: these Macintosh clients require MacTCP.
  3397.  
  3398.      Most of the above clients can also be fetched via a gopher client
  3399.      itself.  Put the following on a gopher server:
  3400.  
  3401.        Type=1
  3402.        Host=boombox.micro.umn.edu
  3403.        Port=70
  3404.        Path=
  3405.        Name=Gopher Software Distribution.
  3406.  
  3407.  
  3408.      Or point your gopher client at boombox.micro.umn.edu, port 70 and
  3409.      look in the gopher directory.
  3410.  
  3411.  
  3412.      There are also a number of public telnet login sites available.
  3413.      The University of Minnesota operates one on the machine
  3414.      "consultant.micro.umn.edu" (134.84.132.4) See Q3 for more
  3415.      information about this.  It is recommended that you run the client
  3416.      software instead of logging into the public telnet login sites.  A
  3417.      client uses the custom features of the local machine (mouse,
  3418.      scroll bars, etc.)  A local client is also faster.
  3419.  
  3420. ---------------------------------------------------------------------
  3421. Q3:  Where are there publicly available logins for Gopher?
  3422.  
  3423. A3:  Here is a short list, use the site closest to you to minimize
  3424.      network lag.
  3425.  
  3426.      Public Logins:
  3427.  
  3428.      Hostname                  IP#              Login   Area
  3429.      ------------------------- ---------------  ------  -------------
  3430.      consultant.micro.umn.edu  134.84.132.4     gopher  North America
  3431.      ux1.cso.uiuc.edu          128.174.5.59     gopher  North America
  3432.      panda.uiowa.edu           128.255.40.201   panda   North America
  3433.      gopher.msu.edu            35.8.2.61        gopher  North America
  3434.      gopher.ebone.net          192.36.125.2     gopher  Europe
  3435.      info.anu.edu.au           150.203.84.20    info    Australia
  3436.      gopher.chalmers.se        129.16.221.40    gopher  Sweden
  3437.      tolten.puc.cl             146.155.1.16     gopher  South America
  3438.      ecnet.ec                  157.100.45.2     gopher  Ecuador
  3439.      gan.ncc.go.jp             160.190.10.1     gopher  Japan
  3440.  
  3441.      It is recommended that you run the client software instead of
  3442.      logging into the public login sites.  A client uses the
  3443.      custom features of the local machine (mouse, scroll bars, etc.)
  3444.      and gives faster response.
  3445.  
  3446. ---------------------------------------------------------------------
  3447. Q4:  How can I add to the information in gopher?
  3448.  
  3449. A4:  You can do this by running a gopher server.  Servers are available
  3450.      for a number of systems.  Use anonymous ftp to
  3451.      boombox.micro.umn.edu (134.84.132.2) and look in /pub/gopher.  The
  3452.      following servers are available there:
  3453.  
  3454.        Unix      : /pub/gopher/Unix/gopher+2.0.tar.Z
  3455.        VMS       : /pub/gopher/VMS/
  3456.        Macintosh : /pub/gopher/Mac_server/
  3457.        VM/CMS    : /pub/gopher/Rice_CMS/ or /pub/gopher/Vienna_CMS/
  3458.        MVS       : /pub/gopher/mvs/
  3459.        DOS PC    : /pub/gopher/PC_server/
  3460.  
  3461.  
  3462.      When you have your server ready you can publish it to the world by
  3463.      sending e-mail to the maintainters of the "Other gophers" list.
  3464.      See Q27 for details.
  3465.  
  3466. ---------------------------------------------------------------------
  3467. Q5:  Who Develops Gopher Software?
  3468.  
  3469. A5:  Gopher was originally developed in April 1991 by the University
  3470.      of Minnesota Microcomputer, Workstation, Networks Center to help
  3471.      our campus find answers to their computer questions.
  3472.  
  3473.      It has since grown into a full-fledged World Wide Information
  3474.      System used by a large number of sites in the world.
  3475.  
  3476.      Many people have contributed to the project, too numerous to
  3477.      count.
  3478.  
  3479.      The people behind the much of the gopher software can be reached
  3480.      via e-mail at gopher@boombox.micro.umn.edu, or via paper mail:
  3481.  
  3482.       Internet Gopher Developers
  3483.       100 Union St. SE #190
  3484.       Minneapolis, MN 55455  USA
  3485.  
  3486.      Or via FAX at:
  3487.  
  3488.       +1 (612) 625-6817
  3489.  
  3490. ---------------------------------------------------------------------
  3491. Q6:  How can I set up a "CSO" phone book server?  Where is the software?
  3492.  
  3493. A6:  CSO phone book servers are also known as "qi" servers.  The
  3494.      software implementation can be gotten via anonymous ftp from
  3495.      uxc.cso.uiuc.edu (128.174.5.50) as /pub/qi.tar.Z.  You may also
  3496.      see this referred to as "ph", which is what most of the clients
  3497.      are called.  A collected set of clients for Macs, PCs, VMS, VM,
  3498.      etc, are in the /pub/ph.tar.Z file.
  3499.  
  3500.      There is also an archive of the mailing list for qi/ph software on
  3501.      the same machine.  It's in /pub/info-ph.archive. You may join the
  3502.      list by sending email to info-ph-request@uxc.cso.uiuc.edu.
  3503.  
  3504.      This software is supported by Paul Pomes <p-pomes@uiuc.edu>
  3505.      Contact him for more information.
  3506.  
  3507. -------------------------------------------------------------------
  3508. Q7:  Why can't I access the University of Minnesota's UPI news?
  3509.  
  3510. A7:  The University of Minnesota has a site license for UPI news, we
  3511.      are not allowed to distribute it off of our campus.  We get our
  3512.      UPI news from Clarinet.  For more information about getting UPI
  3513.      news send mail to info@clarinet.com.  For information about
  3514.      setting up your own gopher-UPI server search the gopher-news
  3515.      archive for UPI.
  3516.  
  3517. -------------------------------------------------------------------
  3518. Q9:  What are the type characters for the different Gopher Objects?
  3519.  
  3520. A9:  Normal IDs.
  3521.  
  3522.      0       Item is a file
  3523.      1       Item is a directory
  3524.      2       Item is a CSO (qi) phone-book server
  3525.      3       Error
  3526.      4       Item is a BinHexed Macintosh file.
  3527.      5       Item is DOS binary archive of some sort.
  3528.      6       Item is a UNIX uuencoded file.
  3529.      7       Item is an Index-Search server.
  3530.      8       Item points to a text-based telnet session.
  3531.      9       Item is a binary file!  Client must read until the connection
  3532.                  closes.  Beware.
  3533.      T       TN3270 connection.
  3534.  
  3535.      Experimental IDs.
  3536.  
  3537.      s       Sound type.  Data stream is a mulaw sound.
  3538.      g       GIF type.
  3539.      M       MIME type.  Item contains MIME data.
  3540.      h       html type.
  3541.      I       Image type.
  3542.      i       "inline" text type (used by panda).
  3543.  
  3544. -------------------------------------------------------------------
  3545. Q10: When I do full-text searches I always get every document back, Why?
  3546.  
  3547. A10: This is a problem occasionally encountered with Unix full-text
  3548.      indexes.  It is caused by setting up the link incorrectly to a
  3549.      gindexd port.
  3550.  
  3551.      The Path= field should be *blank* when pointing to a gindexd
  3552.      index.
  3553.  
  3554.      Otherwise the client will send the path to the gindexd daemon,
  3555.      which interprets everything as a keyword.  This path is
  3556.      likely to contain a pathname that is common to all of the indexed
  3557.      files.  Thus a search generates hits on everything.
  3558.  
  3559.      Note that gindexd isn't used much anymore, this question does not
  3560.      apply if you are using the built in indexing in the Unix gopher
  3561.      server.
  3562.  
  3563. -------------------------------------------------------------------
  3564. Q11: When I try to build the UNIX software I get an error from make:
  3565.      "Must be a separator on rules line #. Stop"  Why?
  3566.  
  3567. A11: This is a problem with older makes that don't understand the "include"
  3568.      keyword.  One easy way to cope with this problem is compiling GNU
  3569.      make, which does understand the include keyword.
  3570.  
  3571.      If this is too difficult, remove the line:
  3572.  
  3573.       include Makefile.config
  3574.  
  3575.      from all the Makefiles and paste in a copy of Makefile.config at
  3576.      the top of each Makefile.
  3577.  
  3578.      Or, instead of pasting you can make the client/server by going
  3579.      into the appropriate directory and typing:
  3580.  
  3581.       make -f ../Makefile.config -f Makefile
  3582.  
  3583. -------------------------------------------------------------------
  3584. Q12: What is the relationship between Gopher and (WAIS, WWW, ftp)?
  3585.  
  3586. A12: Gopher is intimately intertwined with these other systems.
  3587.      As shipped the Unix gopher server has the capability to:
  3588.  
  3589.        - Search local WAIS indices.
  3590.        - Query remote WAIS servers and funnel the results to gopher
  3591.          clients.
  3592.        - Query remote ftp sites and funnel the results to gopher
  3593.          clients.
  3594.        - Be queried by WWW (World Wide Web) clients either using
  3595.          built in gopher querying or using native http querying.
  3596.  
  3597. -------------------------------------------------------------------
  3598. Q13: Are papers or articles describing Gopher available?
  3599.  
  3600. A13: Gopher has a whole chapter devoted to it in :
  3601.  
  3602.      _The_Whole_Internet_users_guide_and_catalog by Ed Krol
  3603.      (publisher O'Reilley & Associates, Inc; ISBN: 1-56592-025-2).
  3604.      (Editors note: ...Great book, go out and buy a bunch!)
  3605.  
  3606.      _The_Internet_Passport: NorthWestNet's Guide to Our World Online"
  3607.      By Jonathan Kochmer and NorthWestNet. Published by NorthWestNet,
  3608.      Bellevue, WA. 1993. 516 pp. ISBN 0-9635281-0-6.
  3609.      Contact info: passport@nwnet.net, or (206) 562-3000
  3610.  
  3611.      _A_Students_Guide_to_UNIX by Harley Hahn. (publisher McGraw Hill,
  3612.      Inc.; 1993 ISBN 0-07-025511-3)
  3613.  
  3614.      _Intelligent_Information_Retrieval:_The_Case_of_Astronomy_and_
  3615.      _Related_Space_Sciences (A. Heck and F. Murtagh, editors). Published
  3616.      by Kluwer Academic Publishers, P.O. box 17, 3300 AA Dordrecht, the
  3617.      Netherlands. ISBN: 0-7923-2295-9
  3618.  
  3619.      Other references include:
  3620.  
  3621.      _The_Internet_Gopher_, "ConneXions", July 1992, Interop.
  3622.  
  3623.      _Exploring_Internet_GopherSpace_ "The Internet Society News", v1n2 1992,
  3624.  
  3625.      (You can subscribe to the Internet Society News by sending e-mail to
  3626.       isoc@nri.reston.va.us)
  3627.  
  3628.      _The_Internet_Gopher_Protocol_, Proceedings of the Twenty-Third
  3629.           IETF, CNRI, Section 5.3
  3630.  
  3631.      _Internet_Gopher_, Proceedings of Canadian Networking '92
  3632.  
  3633.      _The_Internet_Gopher_, INTERNET: Getting Started, SRI
  3634.           International, Section 10.5.5
  3635.  
  3636.      _Tools_help_Internet_users_discover_on-line_treasures, Computerworld,
  3637.           July 20, 1992
  3638.  
  3639.      _TCP/IP_Network_Administration_, O'Reilly.
  3640.  
  3641.       Balakrishan, B. (Oct 1992)
  3642.         "SPIGopher: Making SPIRES databases accessible through the
  3643.       Gopher protocol".  SPIRES Fall '92 Workshop, Chapel Hill, North
  3644.       Carolina.
  3645.  
  3646.       Tomer, C.  Information Technology Standards for Libraries,
  3647.       _Journal of the American Society for Information Science_,
  3648.       43(8):566-570, Sept 1992.
  3649.  
  3650.  
  3651. -------------------------------------------------------------------
  3652. Q14: On a DECstation I get the error message "/etc/svc.conf no such file
  3653.      or directory" when running the gopherd server, why?
  3654.  
  3655. A14: This is caused by the chroot() call in gopherd.  It can be easily
  3656.      fixed by running gopherd with the -c option.
  3657.  
  3658.      Alternatively you can copy /etc/svc.conf into a directory named
  3659.      "etc" inside the gopher-data directory.
  3660. -------------------------------------------------------------------
  3661. Q15: The boolean searching terms don't work for my full-text index, why?
  3662.  
  3663. A15: This is probably because the searching is being provided by WAIS.
  3664.      WAIS opts to return all documents that contain a search phrase
  3665.      within certain limits.  WAIS searches do return the documents with
  3666.      the highest "score" at the top, those documents will have the
  3667.      closest relevance.
  3668.  
  3669.      Alternatively you could get a booleanized version of wais from
  3670.      ftp.bio.indiana.edu, or get the new freeWAIS.
  3671.  
  3672. -------------------------------------------------------------------
  3673. Q16: When linking the Unix gopher server with WAIS I get undefined
  3674.      symbols,
  3675.        such as:
  3676.  
  3677.          log_file_name
  3678.          logfile
  3679.          PrintStatus
  3680.          find_value
  3681.          Sources
  3682.          NumSources
  3683.  
  3684. A17: This happens if you make gopherd before linking in the WAIS ir/ui
  3685.      directories.  The fix is to "make clean" or remove
  3686.      gopherd/{waisgopher.o,Waisindex.o} and then remake gopherd.  Or
  3687.      link the ir/ui directories first.
  3688. -------------------------------------------------------------------
  3689. Q18: Why don't my WAIS indexes work?  I never get anything back for searches.
  3690.      or Why do I get "Dangling file" error messages in my logfile?
  3691.  
  3692. A18: The problem could be in the server.  The server should be run
  3693.      using the -c option if you want WAIS to work.  Another solution is to
  3694.      patch the WAIS code so that it doesn't check the files on the disk.
  3695.      Search the gopher-news archive for "dangling".  This will turn up a
  3696.      single document with the patch.
  3697.  
  3698. -------------------------------------------------------------------
  3699. Q19: My gopher server doesn't work under inetd, why?
  3700.  
  3701. A19: It could be that your inetd server only supports a limited amount
  3702.      of arguments.  For instance, the maximum number of arguments to an
  3703.      inetd server is 5.  You can get around this by combining arguments: i.e.
  3704.  
  3705.        gopherd -I -c
  3706.  
  3707.      becomes:
  3708.  
  3709.        gopherd -Ic
  3710.  
  3711.      You may also leave the port specifier off of the command line.
  3712.      The gopher server automagically finds out the port it's running on.
  3713.  
  3714. -------------------------------------------------------------------
  3715. Q20: This is not a bug report, just a curiousity. I managed to install
  3716.      gopher on my PC, more or less by myself, which is a pretty good
  3717.      accomplishment, for someone who hasn't installed hardly anything on a
  3718.      PC. I then proceeded to load my PC/TCP kernel, ETHDRV, and try to
  3719.      start up gopher. It said it couldn't initialize that stack(?). I have
  3720.      to load this whenever I use PC/TCP. Incredibly, when I did not load
  3721.      ETHDRV, Gopher came up immediately and telneted to our local server.
  3722.      How does it know what kernel to load?
  3723.  
  3724. A20 Dr. Science says,
  3725.  
  3726.      The Internet Gopher program is not actually computer program at
  3727.      all, but a collection of magical incantations handed down from Dark
  3728.      Age conjurors.  It works by sending magical "demons" through the air,
  3729.      which scour the world for information, and then return to cast
  3730.      illusions containing the answer.
  3731.  
  3732.      When you use the Gopher, your computer isn't actually doing
  3733.      anything at all.  Instead, these demons have mesmerized you with an
  3734.      evil magical spell, which was invoked by the pattern of
  3735.      finger-movements peculiar to the typing of the letters G-O-P-H-E-R on
  3736.      your keyboard.  This spell transmits demonic information directly to
  3737.      your brain.
  3738.  
  3739.      Scientists aren't certain of the long-term effects of demonic
  3740.      mesmirization, although former presidents have suffered only minor
  3741.      medical side-effects from it.  Indeed, since Magic and Science are
  3742.      usually opposed to each other, most Scientists are usually
  3743.      close-minded about such issues, and will usually respond with some
  3744.      vacuous non-answer about "packet drivers", "stacks", and other such
  3745.      jargon.
  3746.  
  3747.      Unlike conventional scientists, Dr. Science is very open-minded and
  3748.      is willing to deal with such issues in a frank and honest manner.
  3749.      This is why people come to him with questions, and why they've learned
  3750.      to rely on and live by his answers.
  3751.  
  3752.      Dr. Science
  3753.          "I'm not a real doctor;  I have a Master's Degree....  in SCIENCE!"
  3754.  
  3755. :-) :-) :-) :-)
  3756. There's always room for a little humor in a FAQ..
  3757. -------------------------------------------------------------------
  3758. Q21: Help!  I have PC-NFS and want to use the PC-Gopher client.  How?
  3759.  
  3760. A21: Use a piece of software called PKTMUX, available at fine ftp
  3761.      sites everywhere.  This will let you use any packet driver
  3762.      application.
  3763.  
  3764.      Or, aquire a client that supports PC-NFS.  See Q2.
  3765. -------------------------------------------------------------------
  3766. Q22: How do I nuke a hung TCP connection?  I can't restart my UNIX
  3767.      gopher server unless I get rid of it, and I don't want to reboot!
  3768.  
  3769. A22:
  3770.  
  3771. Here is an example of using dbx to change a socket from CLOSING to
  3772. CLOSED.
  3773.  
  3774.  # netstat -A|grep CLOSING
  3775.  c4bc5100 tcp        0     11  mymachine.gopher 129.89.8.4.70  CLOSING
  3776.  # dbx -k /vmunix /dev/mem
  3777.  ...
  3778.  (dbx) 0xc4bc5100+8/1X                  -- display contents of PCB+8
  3779.  c4bc5108:   00000007
  3780.  (dbx) assign 0xc4bc5108=0              -- zero it
  3781.  0
  3782.  (dbx) q
  3783.  
  3784. After a minute or two, the CLOSED socket should disappear.
  3785. -------------------------------------------------------------------
  3786. Q23: Is there somewhere I can retrieve a list of announced gopher
  3787.      links?  I'd like to keep a local, up-to-date list of available gopher
  3788.      holes without requiring our users to gopher to umn just to scan
  3789.      GopherSpace.
  3790.  
  3791. A23: In the Unix client/server distribution is a perl script called
  3792.      "gopherdist". Gopherdist can fetch the contents of any point in
  3793.      GopherSpace.
  3794.  
  3795.      To dump the contents of all the North American links from
  3796.      gopher.tc.umn.edu do the following:
  3797.  
  3798.      % gopherdist gopher.tc.umn.edu 70 "1/Other Gopher and Information
  3799.        Servers/North America" > .Links
  3800. -------------------------------------------------------------------
  3801. Q24: Why doesn't my unix gopher client display ISO-Latin-1 characters
  3802.      properly?  BTW I'm using a Sun workstation..
  3803.  
  3804. A24: It is the client's problem, the server is perfectly 8-bit transparent.
  3805.      The BSD curses library uses bit 8 in order to remember, whether a
  3806.      character has been displayed reverse. So use just /usr/5bin/cc and
  3807.      you get the System V curses version which is 8 bit clean.
  3808.  
  3809.      Note that this may be a problem under other versions of UNIX too...
  3810.  
  3811. -------------------------------------------------------------------
  3812. Q25: What is veronica?
  3813.  
  3814. A25: veronica:  Very Easy Rodent-Oriented Net-wide Index to
  3815.      Computerized Archives.
  3816.  
  3817.      veronica offers a keyword search of most gopher-server menu titles
  3818.      in the entire gopher web.  As archie is to ftp archives, veronica
  3819.      is to gopherspace.  A veronica search produces a menu of gopher
  3820.      items, each of which is a direct pointer to a gopher data source.
  3821.      Because veronica is accessed through a gopher client, it is easy
  3822.      to use, and gives access to all types of data supported by the
  3823.      gopher protocol.
  3824.  
  3825.      To try veronica, select it from the "Other Gophers" menu on
  3826.      Minnesota's gopher server, or point your gopher at:
  3827.  
  3828.      Name=veronica (search menu items in most of GopherSpace)
  3829.      Type=1
  3830.      Port=70
  3831.      Path=1/veronica
  3832.      Host=futique.scs.unr.edu
  3833.  
  3834. ------------------------------------------------------------------
  3835. Q26: What e-mail discussions lists are active for Gopher?
  3836.  
  3837. A26: There are a couple of places where Gopher software and
  3838.      development is discussed.
  3839.  
  3840.      The USENET newsgroup comp.infosystems.gopher is the biggest
  3841.      discussion list.
  3842.  
  3843.      Gopher discussion also takes place on the mailing list
  3844.      gopher-news.  To subscribe send a message to:
  3845.  
  3846.        gopher-news-request@boombox.micro.umn.edu
  3847.  
  3848.  
  3849.      A mailing list for VMS developers is also available, send e-mail
  3850.      to listserv@trln.lib.unc.edu with a message that contains
  3851.  
  3852.         sub VMSgopher-L firstname lastname
  3853.  
  3854.      A mailing list for MVS gopher developers and users is also
  3855.      available.  To subscribe to the list, send mail to
  3856.      LISTSERVER@LISTS.ACS.OHIO-STATE.EDU containing:
  3857.  
  3858.          SUBSCRIBE MVSGOPHER firstname lastname
  3859.  
  3860.  
  3861. ------------------------------------------------------------------
  3862. Q27: How do I get my Gopher (whois/cso/library catalog) listed in gopher menus?
  3863.  
  3864. A27: If your gopher server is in Europe, send mail to:
  3865.  
  3866.         gopher@ebone.net
  3867.  
  3868.      Otherwise send mail to:
  3869.  
  3870.         gopher@boombox.micro.umn.edu
  3871.  
  3872.      with the following information:
  3873.  
  3874.        The Server's Name (as it will appear on the menu)
  3875.        The Hostname
  3876.        The Port Number
  3877.        An Administrative contact
  3878.        A Selector String (optional)
  3879.  
  3880.  
  3881.      The list of CSO nameservers is maintained at Notre Dame by Joel Cooper.
  3882.      Any updates to the list should be sent to cooper@utopia.cc.nd.edu.
  3883.  
  3884.      The list of WHOIS servers is maintained at MIT by Matt Power.  Any
  3885.      updates to the list should be sent to mhpower@athena.mit.edu.
  3886.  
  3887.      The Gopher to X.500 gateway is maintained  at U. Michigan by Tim Howes.
  3888.      Any comments should be sent to tim@umich.edu.
  3889.  
  3890.      The list of Internet Accessible Libraries is is currently a
  3891.      collaborative effort between Marie-Christine Mahe at Yale
  3892.      University, Lou Rosenfeld at the University of Michigan, and
  3893.      Billy Barron at the University of Texas in Dallas.  Barry Bouwsma
  3894.      steadily contributes many obscure foreign library listings.
  3895.  
  3896.      Error corrections and additions are always welcome, and should be
  3897.      sent to:
  3898.  
  3899.        GOPHLIB@GOPHER.YALE.EDU.
  3900.  
  3901. ------------------------------------------------------------------
  3902. Q28: Where is the registered list of gopher+ view types?
  3903.  
  3904. A28: It's available via anonymous ftp from
  3905.  
  3906.         isi.edu
  3907.  
  3908.       in the directory
  3909.  
  3910.         /in-notes/mime
  3911.  
  3912.  
  3913. --
  3914.  | Paul Lindner | lindner@boombox.micro.umn.edu   | Slipping into madness
  3915.  |              | Computer & Information Services | is good for the sake
  3916.  | Gophermaster | University of Minnesota         | of comparison.
  3917. ///// / / /    /////// / / / /  /  /  /   /      //// / / / /  /  /  /   /
  3918.  
  3919.  
  3920. ./ ADD NAME=MVSFAQ
  3921. MVS Gopher Frequently Asked Questions List
  3922.  
  3923. January 16, 1994
  3924.  
  3925. This list addresses common questions and problems about the MVS
  3926. Gopher client and server.  I hope to update this list and repost
  3927. it to MVSGOPHER on a regular basis, time permitting.
  3928.  
  3929. Note that some items describe restrictions or misfeatures that
  3930. clearly ought to be rectified.  Rest assured that there is a
  3931. "wish list" and these will be included in future releases, but
  3932. only as time permits.
  3933.  
  3934. Thanks to those too numerous to name individually for helping me
  3935. to come up with answers to problems with the installation of MVS
  3936. Gopher on various systems.
  3937.  
  3938. Please feel free to submit additional questions (and answers) to me
  3939. for inclusion or correction.
  3940.  
  3941.         - Steve Bacher (Batchman)       <seb@draper.com>
  3942.         - Draper Laboratory
  3943.  
  3944. ----------------------------------------------------------------------
  3945.  
  3946. Summary of Changes:
  3947.  
  3948.  04 Aug 1993 - added question Q-0
  3949.                updated email addresses
  3950.                public distribution clarified
  3951.  04 Aug 1993 - FAL changed to HAL
  3952.  10 Aug 1993 - V2R2 is on boombox now
  3953.                Added note about MTF and C/370 V1
  3954.  13 Aug 1993 - Another FTP site
  3955.                More info about the MVSGOPHER list itself
  3956.  17 Aug 1993 - Answer to KILL -38 question
  3957.                Removed specific reference to VM LISTSERV
  3958.  31 Dec 1993 - Updated for V3
  3959.  16 Jan 1994 - new email address for Shawn Hart; no longer prerelease
  3960.  
  3961. ----------------------------------------------------------------------
  3962.  
  3963. Summary of Questions:
  3964.  
  3965. Q-0: Why the MVSGOPHER mailing list?
  3966. Q-1: What is Gopher?
  3967. Q-2: Where can I get the MVS Gopher?
  3968. Q-3: How do I get software from SERVICE@USCMVSA?
  3969. Q-4. What do I need to run the MVS Gopher?
  3970. Q-5. Do I need XPROC?  Where can I get it?
  3971. Q-6. Who wrote the MVS Gopher?
  3972. Q-7. Do I have to pay for MVS Gopher?  Who owns it?
  3973. Q-8. Can I use REXX in MVS Gopher?
  3974. Q-9. What is this multitasking problem?
  3975. Q-10. Won't Gopher chew up a lot of CPU resources?
  3976. Q-11. What do I have to do to TCP/IP to use the Gopher client?
  3977. Q-12. What do I have to do to TCP/IP to use the Gopher server?
  3978. Q-13. How do I connect to a different server from the MVS client?
  3979. Q-14. Why can't I run more than one MVS TCP/IP client from TSO?
  3980. Q-15. Where can I get XTELNET?
  3981. Q-16. How do I specify that the MVS Gopher client should use XTELNET?
  3982. Q-17. I get PANEL NOT FOUND errors after using the MVS Gopher.
  3983. Q-18. I get garbage on my screen when Gopher can't open my EXTRACT file.
  3984. Q-19. When I try to run the MVS Gopher Server, I get gethostname errors.
  3985. Q-20. I can't access the "About This Gopher" item of the MVS server.
  3986. Q-21. How do I stop the server?
  3987. Q-22. I can't compile Gopher because...
  3988. Q-23. I can't linkedit Gopher because...
  3989. Q-24. I can't run the Gopher server because...
  3990. Q-25. I can't run the Gopher client because...
  3991. Q-26. I can't run the Gopher server or client because...
  3992. Q-27. I get an 0C1 ABEND when I try to run the server/client
  3993. Q-28. I can't figure out how to define the main Gopher menu to the server.
  3994. Q-29. Why doesn't the Gopher client honor my additional parameters,
  3995. Q-30. Why can't I attention out of the Gopher client?
  3996. Q-31. Why do I have to "S" (select) an item before I can "E" (extract) it?
  3997. Q-32. Where's the tutorial?
  3998. Q-33. What's the deal with the "w" type?
  3999. Q-34. How can I debug a Gopher server REXX exec?
  4000. Q-35. What hostname and port hacks?
  4001. Q-36. What MVS file types does the Gopher server support?
  4002. Q-37: How can I display square brackets while viewing text?
  4003. Q-38: How can I make the client start up at a specific bookmark file?
  4004. Q-39: Can I set up client items that do anything my users would want?
  4005.  
  4006. ----------------------------------------------------------------------
  4007.  
  4008. Q-0: Why the MVSGOPHER mailing list?
  4009.  
  4010. A. It's much harder to get a USENET newsgroup started than a private
  4011. mailing list.  The procedure for creating a new newsgroup is
  4012. considerably more formal and involves lots of voting.
  4013.  
  4014. It's true that we could use comp.infosystems.gopher or IBMTCP-L, but
  4015. both of those have plenty of traffic as it is, and there are issues
  4016. pertaining to MVS Gopher that would bore the other readers.
  4017.  
  4018. It is possible to gateway mailing lists to newsgroups locally.
  4019.  
  4020. List servers offer the following options that the user can control
  4021. via email. One may choose to have mail delivered...
  4022. (1) as usual - that is, as mail is sent to the list it is resent
  4023.     to you; this seems to be what you object to
  4024. (2) you may receive a digest - daily, weekly, monthly, your choice -
  4025.     where all mail distributed is sent to you as a package
  4026. (3) opt NOT to receive email and instead persuse the distributed mail
  4027.     at your convenience using special commands  sent to the server
  4028.     by email; you can opt to read only new mail (since a certain date),
  4029.     only mail about certain topics, from certain people, whatever you
  4030.     choose;
  4031.  
  4032. Should a newsgroup be set up, a list server will also allow all email
  4033. sent to it to automatically be posted to the newsgroup.
  4034.  
  4035. So, if you're not already on the list, you can join by sending a
  4036. message with "SUBSCRIBE MVSGOPHER yourfirstname yourlastname" to
  4037. LISTSERVER@LISTS.ACS.OHIO-STATE.EDU.
  4038.  
  4039. ----------------------------------------------------------------------
  4040.  
  4041. Q-1: What is Gopher?
  4042.  
  4043. A. Gopher is a distributed information delivery service.  That sounds
  4044. quite boring, which is why people prefer the name "gopher".  The
  4045. original Gopher came out of the University of Minnesota and ran
  4046. on Unix machines.  Subsequently it has been ported to virtually
  4047. every known architecture, both clients and servers.  Thus, a Gopher
  4048. client on MVS can access data being served by any other kind of
  4049. machine, and a Gopher server on MVS can allow clients on any
  4050. platform to read mainframe data.
  4051.  
  4052. If you really want to know all about Gopher, read the Gopher FAQ
  4053. posting on the comp.infosystems.gopher newsgroup.  This FAQ, and
  4054. the mailing list that owns it, are for Gopher on MVS only.
  4055.  
  4056. ----------------------------------------------------------------------
  4057.  
  4058. Q-2: Where can I get the MVS Gopher?
  4059.  
  4060. A. The MVS Gopher client and server is available via anonymous FTP from:
  4061.  
  4062.  boombox.micro.umn.edu          /pub/gopher/mvs
  4063.  ftp.mic.ucla.edu               /pub/mvs/gopher
  4064.  info2.rus.uni-stuttgart.de     /pub/comm/infosystems/gopher/mvs
  4065.  
  4066. Latest MVS Gopher on boombox.micro.umn.edu:       Version 2 Release 2
  4067. Latest MVS Gopher on ftp.mic.ucla.edu:            Version 3 Release 1
  4068. Latest MVS Gopher on info2.rus.uni-stuttgart.de:  Version 2 Release 2
  4069.  
  4070. Although the entire Gopher package is included in the single giant
  4071. JCL stream that the distribution consists of, you don't have to
  4072. install it all.  You can install just the server or just the client
  4073. if that's all you're interested in.  The README file for the latest
  4074. version/release explains how to FTP the distributions.
  4075.  
  4076. You also have the choice of getting either the C language source or the
  4077. precompiled object code.  Also, the UCLA site has more up-to-date
  4078. releases, including beta releases.  The boombox version is frequently a
  4079. release or two behind, since it is intended to be the "reliable" version.
  4080.  
  4081. ----------------------------------------------------------------------
  4082.  
  4083. Q-3: How do I get software from SERVICE@USCMVSA?
  4084.  
  4085. A. You can't.  This service was discontinued on August 31, 1993.
  4086. Use the FTP site at ftp.mic.ucla.edu instead.  For more information,
  4087. contact Leonard Woren <ldw@usc.edu>.
  4088.  
  4089. ----------------------------------------------------------------------
  4090.  
  4091. Q-4. What do I need to run the MVS Gopher?
  4092.  
  4093. A. C/370 Version 2 (SAS/C support is not currently available but
  4094. is under development)
  4095.  
  4096.  Note:  C/370 Version 1 may be OK for the client, but the server
  4097.  definitely needs C370 version 2.
  4098.  
  4099. IBM TCP/IP or Interlink SNS/TCPaccess
  4100.  
  4101. ISPF V2R2 or higher.  V3 for best results, otherwise you
  4102. may be forced to do a lot of hand-hacking of the panels.
  4103.  
  4104. TSO/E V2 or higher to use the REXX interface.  Some of the new
  4105. capabilities in the MVS Gopher V3 REXX interface require REXX 3.46,
  4106. which is available with TSO/E V2.3.1.
  4107.  
  4108. If you don't have any C compiler, you can get the object code
  4109. distribution (see answer to above question).  However, in that
  4110. case, you must have the IBM C/370 runtime library installed,
  4111. since the object code was compiled with C/370 Version 2.
  4112. Also, you must be running IBM TCP/IP (HAL) V2 and ISPF V3.
  4113.  
  4114. ----------------------------------------------------------------------
  4115.  
  4116. Q-5. Do I need XPROC?  Where can I get it?
  4117.  
  4118. A. Until recently, you needed XPROC if you wanted to be able to
  4119.    pass parameters to the GOPHER client TSO command (REXX exec).
  4120.    Now, there is some REXX parsing code that can simulate the
  4121.    TSO parameter extraction.  But you're still better off using
  4122.    XPROC if you want truly robust parsing.
  4123.  
  4124.    XPROC is available from ftp.mic.ucla.edu (the same as one of
  4125.    the Gopher source sites, if you're sharp-eyed), in directory
  4126.    /pub/mvs/util. It's in the TSOREXX distribution, which also
  4127.    includes the XWRITENR utility (which emulates TSO CLIST
  4128.    WRITENR for REXX execs).
  4129.  
  4130. ----------------------------------------------------------------------
  4131.  
  4132. Q-6. Who wrote the MVS Gopher?
  4133.  
  4134. A. The MVS Gopher Server was originally by Shawn Hart at the
  4135.    University of Delaware.  Subsequently, Steve Bacher made
  4136.    enhancements to it, and also wrote the client.  Shawn Hart
  4137.    is currently at shart@indial1.io.com.
  4138.  
  4139.    Various enhancements and customizations to both the client and
  4140.    the server have been contributed by:
  4141.  
  4142.     Lou Joseph     <cwmy5c@irishmvs.cc.nd.edu>
  4143.     Denis DeLaRoca <csp1dwd@mvs.oac.ucla.edu>
  4144.     Dwight Cook    <sysdc@uokmvsa.backbone.uoknor.edu>
  4145.     Rachna Agrawal <rachna@clemson.clemson.edu>
  4146.  
  4147. ----------------------------------------------------------------------
  4148.  
  4149. Q-7. Do I have to pay for MVS Gopher?  Who owns it?
  4150.  
  4151. A. MVS Gopher is distributed publicly for free, but is not in
  4152.    the public domain.
  4153.  
  4154.    Here is the standard disclaimer:
  4155.  
  4156.  Copyright (c) The Charles Stark Draper Laboratory, Inc.,1992,1993,1994
  4157.  
  4158.  MVS Gopher Server originally by Shawn Hart (Univ. of Delaware).
  4159.  
  4160.  This software is provided on an "AS IS" basis.  All warranties,
  4161.  including the implied warranties of merchantability and fitness,
  4162.  are expressly denied.
  4163.  
  4164.  Provided this copyright notice is included, this software may
  4165.  be freely distributed and not offered for sale.
  4166.  
  4167.  Changes or modifications may be made and used only by the maker
  4168.  of same, and not further distributed.  Such modifications should
  4169.  be mailed to the author for consideration for addition to the
  4170.  software and incorporation in subsequent releases.
  4171.  
  4172. ----------------------------------------------------------------------
  4173.  
  4174. Q-8. Can I use REXX in MVS Gopher?
  4175.  
  4176. A. The server has a REXX interface:  you can define menu items
  4177.    which fire up REXX execs in the server's address space.
  4178.    However, beware of the multitasking problem.
  4179.  
  4180.    MVS Gopher V3 has a completely reworked interface which
  4181.    solves the "multitasking problem" by allowing REXX execs
  4182.    to run outside of a TSO environment.  However, TSO/E 2.3.1
  4183.    is required for this (see Q-4).
  4184.  
  4185.    Also, the client is driven by a REXX exec as a TSO command.
  4186.  
  4187. ----------------------------------------------------------------------
  4188.  
  4189. Q-9. What is this multitasking problem?
  4190.  
  4191. A. Due to TSO/E architectural limitations, a Gopher server that runs
  4192.    REXX execs in a TSO environment must be single-threading.  However,
  4193.    you can run more than one Gopher server at a time, so this is not a
  4194.    show-stopper.  You can run a multithreading Gopher server that
  4195.    services only files, and a singlethreading Gopher server that
  4196.    services files and REXX exec services.  You simply set up different
  4197.    GGPARMS files - one says "MTFTASKS 1" and the other says "MTFTASKS 8"
  4198.    or whatever number you want.  They must also have differing port
  4199.    numbers (e.g. one at port 70 and one at port 1570).
  4200.  
  4201.    MVS APAR OY20253 addresses multitasking problems with TSO services.
  4202.    For TSO/Extensions V2R3, just to take one instance, PTFs UY35936 and
  4203.    UY35937 address these, but have a long PE chain against them.
  4204.    Upgrading TSO/E from V2R3 to V2R4 might help resolve these, but
  4205.    you're still stuck with the basic design of TSO, which is definitely
  4206.    not friendly to concurrency.  Take ddnames (please).  Dynamic
  4207.    allocation that uses preset ddnames is clearly not going to work
  4208.    well in a concurrent TSO environment.
  4209.  
  4210.    The most obvious difficulty used to be that the Gopher-REXX
  4211.    interface requires that REXX execs write to SYSTSPRT.  Clearly more
  4212.    than one can't do this at the same time.  This has changed in MVS
  4213.    Gopher V3, which has a completely new REXX interface.  This solves
  4214.    the "multitasking problem" by allowing REXX execs to run without a
  4215.    TSO environment.  Note that TSO/E 2.3.1 is required for this (see
  4216.    Q-4).  Also, if you want to write REXX execs that use TSO services
  4217.    or call programs that require specific ddnames, you are still stuck
  4218.    with the need to run them under a single-threading Gopher server.
  4219.  
  4220. ----------------------------------------------------------------------
  4221.  
  4222. Q-10. Won't Gopher chew up a lot of CPU resources?
  4223.  
  4224. A. The client won't, because it's just an ISPF dialog program
  4225.    that makes a lot of short, brief network connections.  If you're
  4226.    still running V1, though, you will use up a lot of CPU in the ISPF
  4227.    browse interface, which was totally rewritten in V2.
  4228.  
  4229.    The server does somewhat more work, but (unlike the CMS gopher
  4230.    server, which is written in REXX), it's written in C, so it's
  4231.    reasonably fast.  However, if you write REXX execs to serve some
  4232.    Gopher items, they will obviously chew up CPU resources, depending
  4233.    on what they do.
  4234.  
  4235.    If you want to get an idea of usage, start with the gopher server
  4236.    log, which you can see as part of the regular output of the gopher
  4237.    server (e.g. via SDSF).  Also, if you have enabled them, you can use
  4238.    the write-to-programmer messages issued by the Gopher server, which
  4239.    are compatible with the UMn-format messages (I don't believe that
  4240.    the look and feel of these messages has been patented yet).
  4241.  
  4242. ----------------------------------------------------------------------
  4243.  
  4244. Q-11. What do I have to do to TCP/IP to use the Gopher client?
  4245.  
  4246. A. No special action is required for the client.  However, if
  4247.    your users are likely to run more than one TCP/IP client
  4248.    socket application from the same TSO session, then make sure
  4249.    that you have the "IUCVMULT" PTF for IBM's HAL.  See Q-14.
  4250.  
  4251. ----------------------------------------------------------------------
  4252.  
  4253. Q-12. What do I have to do to TCP/IP to use the Gopher server?
  4254.  
  4255. A. For IBM (HAL) TCP/IP...
  4256.  
  4257.    The following is from the installation instructions for the server:
  4258.  
  4259.    Add the name of the Gopher server started task (the name as it
  4260.    appears in SYS1.PROCLIB, not necessarily "GOPHER") to the MVS TCPIP
  4261.    profile data set (or have your MVS TCP/IP system programmer do it).
  4262.    In the examples below, let's say you've called it GOPHSRV.  Add this
  4263.    in 2 places:
  4264.  
  4265.    (a) under AUTOLOG, so that TCP/IP will start the Gopher server
  4266.        automatically (a la inetd for unix) when a client connects.
  4267.        Just add the name to the list (e.g. GOPHSRV).
  4268.  
  4269.    (b) under PORT, so nobody can spoof the Gopher port.  The format
  4270.        here is:   70 TCP GOPHSRV
  4271.  
  4272.    Repeat both for whatever number of Gopher server started tasks you
  4273.    create (with different port numbers).
  4274.  
  4275.    For Interlink SNS/TCP...
  4276.  
  4277.    By permission of the author:
  4278.  
  4279.    posted to IBMTCP-L on 27 May 1993 by Lou Joseph
  4280.    <CWMY5C%IRISHMVS.CC.ND.EDU@uicvm.uic.edu>
  4281.  
  4282.    I have looked further and found another place where
  4283.    the hostname is given.  I think that this one is more likely to be used
  4284.    by gethostname().  It is in member DNRALCnn in SNSTCP.V110.PARM.  Here is
  4285.    a copy of our DNRALC01:
  4286.  
  4287.    ACSS      IRISHMVS.CC.ND.EDU. OUR SNS/TCP SUBSYSTEM NAME
  4288.    LOOPBACK  127.0.0.1           SNS/TCP LOCAL HOST NAME
  4289.    LOCALHOST 127.0.0.1           SNS/TCP LOCAL HOST NAME
  4290.  
  4291.    ACSS is the SNS/TCPaccess Subsystem Name.  Note that there is a period
  4292.    after the EDU in the first line.
  4293.  
  4294.    Lou
  4295.  
  4296.    Lou Joseph                             CWMY5C@IRISHMVS.BITNET
  4297.    Office of University Computing         Louis.Joseph.2@ND.EDU
  4298.    University of Notre Dame
  4299.    Room G005 CCMB
  4300.    Notre Dame, IN 46556                   (219) 631-7055
  4301.  
  4302. ----------------------------------------------------------------------
  4303.  
  4304. Q-13. How do I connect to a different server from the MVS client?
  4305.  
  4306. A. Use the syntax GOPHER SERVER(other.server.host).  You should have
  4307.    XPROC available for your GOPHER command to parse this in the most
  4308.    reliable fashion (see Q-5).
  4309.  
  4310.    You can also connect to another server by modifying your GOPHERRC
  4311.    data set (or specifying an alternate one with the INITFILE keyword,
  4312.    new in Gopher V3).  Your default GOPHERRC file will have a section
  4313.    in it that looks something like this:
  4314.  
  4315.    Initial:
  4316.  
  4317.    Type=DIRECTORY
  4318.    Name=Primary (Root) Gopher Menu
  4319.    Path=
  4320.    Host=mvs.draper.com
  4321.    Port=70
  4322.    End
  4323.  
  4324.    Just remove that section (or comment it out by sticking "#" characters
  4325.    in front of the lines) and Gopher will prompt you for a server name.
  4326.    Or else you can replace the value of the Host= line with the server
  4327.    you want to connect to.  For example, change
  4328.  
  4329.    Host=mvs.draper.com
  4330.  
  4331.    to
  4332.  
  4333.    Host=testhost.elsewhere.com
  4334.  
  4335. ----------------------------------------------------------------------
  4336.  
  4337. Q-14. Why can't I run more than one MVS TCP/IP client from TSO?
  4338.  
  4339. A. (sigh) Do you really want to know?
  4340.  
  4341.   IBM TCP/IP for MVS has had difficulties in managing more than one
  4342.   active client application per MVS/TSO address space.
  4343.  
  4344.   There were several parts to this problem:
  4345.  
  4346.   (1) Applications that use C language sockets cannot coexist with
  4347.       each other
  4348.  
  4349.   (2) Applications that use C language sockets cannot coexist with
  4350.       applications that use the Pascal-based interface
  4351.  
  4352.   (3) Applications that use the Pascal-based interface cannot
  4353.       coexist with each other
  4354.  
  4355.   As a consequence of (2) and (3), if an application using the
  4356.   Pascal-based interface is active, no other client application,
  4357.   either Pascal-based or socket-based, can be active in the same
  4358.   MVS address space.
  4359.  
  4360.   In TCP/IP for MVS Version 2 Release 1,
  4361.   IBM has partially solved (1), but has not solved (2) or (3).
  4362.  
  4363.   The solution involved creating a new module called IUCVMULT which would
  4364.   be loaded into the environment to track IUCV identifications within an
  4365.   address space.  IUCVMULT is a serially reusable module, so that there
  4366.   is one shared copy per address space.  Since IUCVMULT is loaded by the
  4367.   first call to a C socket routine, the first C socket application in the
  4368.   address space must hang around, which is potentially disastrous.
  4369.  
  4370.   This solution has several weaknesses:
  4371.  
  4372.           * The aforementioned requirement that IUCVMULT must be loaded
  4373.             in such a way as to allow all clients to see the same copy.
  4374.  
  4375.           * It does not address the problem of non-socket applications.
  4376.  
  4377.           * The requirement for the first socket application to remain
  4378.             active as long as the user needs to run any socket clients
  4379.             carries the potential for disaster.  It means that a user
  4380.             cannot start application X, then start application Y, then
  4381.             terminate application X without crashing application Y.
  4382.             It also requires the user to remember which application
  4383.             was brought in "first", when in the ideal world the user
  4384.             should not even have to know if a given application is a
  4385.             TCP/IP client or not.
  4386.  
  4387.           * In a multiple-job-step-TCB environment (e.g. IMS), or a
  4388.             multi-session vendor product like TSC's PIE MultiTSO, which
  4389.             creates multiple job step TCB's with separate job pack areas,
  4390.             it is possible to have TCP/IP socket applications under
  4391.             different sessions at the same time with distinct copies
  4392.             of IUCVMULT.  This produces disastrous results, as it
  4393.             has been known to cause the TCP/IP address space to crash.
  4394.  
  4395.   IBM shipped PTF UN13465 for APAR PL83602.  Results showed that we were
  4396.   able to run our C socket application, fire up FTP while it was active,
  4397.   and not crash the socket application.  However, firing up a second FTP
  4398.   in this environment caused an ABEND.
  4399.  
  4400.   One way to get around this, once you have the IUCVMULT fix, is
  4401.   to use Denis DeLaRoca's XTELNET instead of TELNET.
  4402.  
  4403. ----------------------------------------------------------------------
  4404.  
  4405. Q-15. Where can I get XTELNET?
  4406.  
  4407. A. From ftp.mic.ucla.edu, directory /pub/mvs/xtelnet.
  4408.  
  4409. ----------------------------------------------------------------------
  4410.  
  4411. Q-16. How do I specify that the MVS Gopher client should use XTELNET?
  4412.  
  4413. A. If you have V2R2, you can put the following line in your
  4414.    GOPHERRC file:
  4415.  
  4416.    Telnet: XTELNET
  4417.  
  4418.    If you want to make this change for everyone, then you must install
  4419.    the Gopher client in such a way as to insure that all GOPHERRC
  4420.    files are built in the correct way.  There is code in the GOPHER
  4421.    exec that sets the value of the TELNET command, as well as a few
  4422.    other things.  Use that to establish XTELNET as a default.
  4423.  
  4424. ----------------------------------------------------------------------
  4425.  
  4426. Q-17. I get PANEL NOT FOUND errors after using the MVS Gopher.
  4427.  
  4428. A. You're using ISPF LIBDEF.  LIBDEF is broken because it blows away
  4429.    previously set LIBDEFs.  LIBDEF should be used only for testing
  4430.    ISPF applications, not production.  Copy the ISPF panels and
  4431.    the GGCLIENT load module into production libraries - i.e. the
  4432.    ones all TSO users get at logon time - and ditch LIBDEF.  For
  4433.    more information, try contacting the SHARE ISPF project to hear
  4434.    their whole sad story.
  4435.  
  4436. ----------------------------------------------------------------------
  4437.  
  4438. Q-18. I get garbage on my screen when Gopher can't open my EXTRACT file.
  4439.  
  4440. A: The problem is that CBIPO, at least up through 92A, ships a
  4441.    broken C/370 runtime -- they installed all the FMIDs, so you get
  4442.    execution error messages in Kanji.  perror() calls to stderr are
  4443.    what are affected.
  4444.  
  4445.    In other words, you have FMID JCLB212 installed instead of JDL1214,
  4446.    JCLB212 is the Kanji messages feature.  JDL1214 is the messages for
  4447.    the Common Library.  For C without PL/1, apparently you weren't
  4448.    supposed to install a separate FMID for messages at all.
  4449.  
  4450.    Solution 1:  Install JDL1214 and hope it clobbers the other one!
  4451.                 (But it won't.)
  4452.    Solution 2:  Uninstall JCLB212.
  4453.    Solution 3:  Order C/370 from IBM and start over from scratch.
  4454.  
  4455.    Neither of the above has been tried by anyone, to my knowledge.
  4456.  
  4457.    Also see Q-22.
  4458.  
  4459. ----------------------------------------------------------------------
  4460.  
  4461. Q-19. When I try to run the MVS Gopher Server, I get gethostname errors.
  4462.  
  4463. A. Thanks to Mike Porter at the University of Delaware for this reply,
  4464.    posted to IBMTCP-L on 27 May 1993.
  4465.  
  4466. One problem we've been seeing with 'gopher' and 'gethostname'
  4467. really has nothing to do with either.  Its just that this is
  4468. the most common socket application our users run.  (finger
  4469. doesn't work either - for instance, nor will any socket call.)
  4470.  
  4471. I spent some time tracking down the problem, but got lost in the
  4472. platform support code.  What seems to happen is a control block
  4473. that is created once per session gets left around when an address
  4474. space terminates.  All future attempts to do an IUCV_set will fail
  4475. until an IPL occurs.
  4476.  
  4477. This is sort of like the old 'can't run two tcp/ip applications
  4478. from the same address space', but not exactly.  The old problem
  4479. would clear up when the user would log off, but in this case,
  4480. apparently MVS needs to be ipled.  Perhaps the resource manager is
  4481. not cleaning up like it should?
  4482.  
  4483. One way to see if this is the problem is to run MVPXDISP (its in
  4484. SEZALINK, and needs to be authorized, so add it to the auth. cmd
  4485. list and update the tso parms.  And no, it won't run in batch).
  4486.  
  4487. This is the output received for a user that can't run gopher:
  4488.  
  4489. MVPMVP656I MVPXDISP: VMCF: Pending count=1 Flags=40000000.
  4490. MVPMVP655I MVPXDISP: IUCV: Connections=1, Max=255.
  4491. MVPMVP662I MVPXDISP: IUCV: Ctl flags=00000000 Appl flags=00000000.
  4492. MVPMVP650I MVPXDISP: User MIS0175  Asid 00A5.                   *****
  4493. MVPMVP651I MVPXDISP: Data @ 0302A5C0 Sm=00 Cr0=000000E3 Flags=38.
  4494. MVPMVP652I MVPXDISP: Client of the VMCF address space.
  4495. MVPMVP652I MVPXDISP: Client of IUCV.
  4496. MVPMVP653I MVPXDISP:  IUCV mask=F8F8, Pending Ctl=0000, Appl=0820.
  4497. MVPMVP654I MVPXDISP: VMCF: Buf=002E9030, Len=00000118, Flgs=00 User=
  4498.                      Key=80.
  4499.  
  4500. A talk with level 1 yields a solution of 'use another userid' or
  4501. 'ipl' (stopping and restarting the tcpip address space doesn't
  4502. help since the data appears to be associated with the subsystem).
  4503.  
  4504. A: Here's something for SNS/TCP users with gethostname problems:
  4505.  
  4506.  From:    Lou Joseph <CWMY5C%IRISHMVS.CC.ND.EDU@uicvm.uic.edu>
  4507.  Subject: Re: gethostname under MVS
  4508.  
  4509.  There is a configuration member in SNSTCP.V110.SAMP named ACPCONFG.  It
  4510.  has to be customized, assembled and linked into SNSTCP.V110.LOAD.
  4511.  There is a MACRO ACFHOST in ACFCONFG with keywords MEMBER and DOMAIN.
  4512.  We have MEMBER=IRISHMVS and DOMAIN=CC.ND.EDU.
  4513.  
  4514.  That's the only place I could find where the local host name is set.
  4515.  
  4516.  Lou
  4517.  
  4518. ---
  4519.  
  4520. (In the old days I used to require that you stick the host name into
  4521. the source code somewhere, but that kind of went away when I realized
  4522. that gethostname() would do it.  So I don't remember where or how I
  4523. would insert the host name now. - seb)
  4524.  
  4525. ----------------------------------------------------------------------
  4526.  
  4527. Q-20. I can't access the "About This Gopher" item of the MVS server.
  4528.  
  4529. A. This is because of a limitation that has been fixed in V2R3 of
  4530.    MVS Gopher.  In the distributed installation instructions, it
  4531.    suggets that the "About This Gopher" PDS is to be referenced in
  4532.    the menu as PATH=DD:GGABOUT(ABOUT).  This is what's in the
  4533.    sample server JCL.
  4534.  
  4535.    However, if you do this, then the subentries of this menu
  4536.    won't work, because they use the PATH=(MEMBER) feature, which
  4537.    didn't work when the current PDS was specified using the DD:
  4538.    format.  V2R3 allows this.  But in the meantime, read the
  4539.    note in the installation instructions that says to change
  4540.    the menu entry from PATH=DD:GGABOUT(ABOUT) to
  4541.    PATH=DATA.SET.NAME(ABOUT), where DATA.SET.NAME is the name
  4542.    of your "ABOUT" PDS.
  4543.  
  4544. ----------------------------------------------------------------------
  4545.  
  4546. Q-21. How do I stop the server?
  4547.  
  4548.    The MVS Gopher server, being a plain C program, doesn't understand
  4549.    operator "STOP" commands.  Just use the operator "CANCEL" command
  4550.    from the console.  For example, if you installed it as GOPHSRV in
  4551.    'SYS1.PROCLIB' you would start it via:
  4552.  
  4553.     START GOPHSRV     or    S GOPHSRV
  4554.  
  4555.    and you would stop it by
  4556.  
  4557.     CANCEL GOPHSRV    or    C GOPHSRV
  4558.  
  4559.    It'll come down with a system 222 ABEND, which looks ugly, but is
  4560.    really quite harmless.
  4561.  
  4562. ----------------------------------------------------------------------
  4563.  
  4564. Q-22. I can't compile Gopher because...
  4565.  
  4566. Q. It says it can't find the header file "time.h".
  4567.  
  4568. A: Leonard Woren had this problem with C/370 1.1 and then again with
  4569.    V2.  The problem is that C/370 is shipped with TIME as a MAC, which
  4570.    collides with the MVS TIME macro when C/370 is installed in the same
  4571.    zone as MVS.  The CBIPO build ignores the error message about this,
  4572.    and ships a non-usable C/370.  There's a PTF which adds EDCMTIME
  4573.    with an MALIAS of TIME to fix this problem.  The PTF for HCCM202 is
  4574.    UN12293.  Note that spc.h has the same problem, which is fixed by
  4575.    UN17425 (EDCMSPC).  Also note that CBIPO, at least up through 92A,
  4576.    ships a broken C/370 runtime -- they installed all the FMIDs, so you
  4577.    get execution error messages in Kanji.  See Q-18.
  4578.  
  4579. ----------------------------------------------------------------------
  4580.  
  4581. Q-23. I can't linkedit Gopher because...
  4582.  
  4583. Q. I get TABLE OVERFLOW ... TOO MANY EXTERNAL SYMBOLS IN ESD
  4584.  
  4585. A. The SYSLIB should point to 'TCPIP.COMMTXT' or 'TCPIP.SEZACMTX'
  4586.    depending on the level of TCP/IP.  If you're pointing it at
  4587.    'TCPIP.COMMMAC' or 'TCPIP.SEZACMAC', then of course your link
  4588.    is going to lose big.
  4589.  
  4590. Q. it says that ATEXIT is multiply defined
  4591.  
  4592. A. Under certain circumstances, people get a linkage editor warning
  4593.    when they build Gopher, saying that ATEXIT is multiply defined.  It
  4594.    is because the C/370 MTF (multitasking) library has a different
  4595.    atexit() from the normal C library.  Make sure that the linkedit of
  4596.    load module GGSTASK has the INCLUDE SYSLIB(EDCMTFS) control
  4597.    statement, and that the linkedit of load module GGSERVER (or
  4598.    GGSERVE, in Gopher V3) does *not* have an INCLUDE SYSLIB(EDCMTFS)
  4599.    control statement.
  4600.  
  4601. Q. it can't find FCNTL or MTF or mtf.h
  4602.  
  4603. A. You can't use C/370 V1 with the server.  Get C/370 V2 or stick
  4604.    with the client only.  If you stick with the client and your
  4605.    problem is that include file mtf.h is not found, then you'll
  4606.    have to remove that line from header file GG before continuing.
  4607.  
  4608. ----------------------------------------------------------------------
  4609.  
  4610. Q-24. I can't run the Gopher server because...
  4611.  
  4612. Q. it gets an 0Cx abend
  4613.  
  4614. A. Did you just install TCP/IP 2.2.1 and forget to relink your Gopher
  4615.    with the 2.2.1 TCP/IP routines?
  4616.  
  4617. Q. it gets "The GIVESOCKET timed out"
  4618.  
  4619. A. Not sure, but this went away for some users when they
  4620.    upgraded their TCP/IP...
  4621.  
  4622. Q. I get: TCPIP severed IUCV path. Reason 'KILL -38 '
  4623.  
  4624. A. Chuck Sechler <TS0258@ohstmvsa.acs.ohio-state.edu> says:
  4625.    We get this every time we shut down the system.  When we shut down,
  4626.    we do not CANCEL GOPHER, but we stop TCPIP.  I always assumed that
  4627.    this severed a connection with GOPHER, which led to the KILL -38
  4628.    message.  This also leads to an ABEND for GOPHER of A03, which seems
  4629.    plausible.
  4630.  
  4631. Q. the subtasks get weird abends
  4632.  
  4633. A. Make sure that you're not running REXX exec requests from a
  4634.    server that runs under s TSO environment and is multithreading
  4635.    (MTFTASKS > 1).  See Q-8.
  4636.  
  4637. Q. I get EINVAL errors on GIVESOCKET and/or ABENDA03
  4638.  
  4639. A. Perhaps you are running SIMTCPIP from SIMWARE, which relinks
  4640.    the entire Gopher module?  In effect, this is running TCPIP 2.1
  4641.    with a Gopher that has TCPIP 2.2 stuff linked in.
  4642.  
  4643. Q. I get gethostname() failures
  4644.  
  4645. A. See Q-19.  If that doesn't apply, make sure you've got the
  4646.    latest MVS Gopher, because I've fixed a lot of bugs in this.
  4647.    One user had been linking their Gopher with the wrong copy of
  4648.    CMMVSYS, which defines the IBM TCP/IP address space name!
  4649.  
  4650. Q. I'm getting 001 ABENDS on the SYSTSPRT file.
  4651.  
  4652. A. You need to debug your REXX execs (see Q-34).  You could be
  4653.    allocating not enough space in your server JCL to hold a lot
  4654.    of output, or there could be trash being spewed out by your
  4655.    REXX exec.
  4656.  
  4657.    Actually, this whole problem will go away if you get MVS Gopher V3,
  4658.    which has a whole new REXX interface.  But you'll have to stop
  4659.    writing to SYSTSPRT.
  4660.  
  4661. Q. I get "Unknown host MVS.DRAPER.COM"
  4662.  
  4663. A. You need to configure the server.  You can do this by specifying
  4664.    "DOMAIN my.actual.site" in the GGPARMS startup file in the server.
  4665.    If you have the source code distribution, you can also accomplish
  4666.    this by changing the value of the MY_DOMAIN_SUFFIX preprocessor
  4667.    variable in the GGUSER header file.
  4668.  
  4669. ----------------------------------------------------------------------
  4670.  
  4671. Q-25. I can't run the Gopher client because...
  4672.  
  4673. Q. I get "The parallel load module was not found.  Could not set up
  4674.    the TCP environment."
  4675.  
  4676. A. You need C/370 V2 and you must make sure that you linkedit the
  4677.    server with the "INCLUDE SYSLIB(EDCMTFS)" line.
  4678.  
  4679. Q. I get "Unknown host MVS.DRAPER.COM"
  4680.  
  4681. A. You need to configure the client.  You can do this by modifying
  4682.    the GOPHERRC file (or modifying the code in the GOPHER exec that
  4683.    creates the GOPHERRC file for new users), or, if you have the
  4684.    source code distribution, by changing the value of the
  4685.    MY_DOMAIN_SUFFIX preprocessor variable in the GGUSER header file.
  4686.  
  4687. Q. I get "Unknown host FOO.MYDOMAIN.NAME"
  4688.  
  4689. A. You need to talk to whoever maintains your MVS TCP/IP site and
  4690.    ask about host tables and domain name servers.  Tell them that
  4691.    MVS socket applications are not recognizing hostnames with the
  4692.    local domain name included when they do gethostname() calls,
  4693.    and gethostbyname() is not working when the domain name is
  4694.    included.  If that doesn't help, try changing the value of the
  4695.    APPEND_DOMAIN_NAME_TO_SELF preprocessor variable in the GGUSER
  4696.    header file - but this may cause other servers to become
  4697.    impossible to reach.
  4698.  
  4699. ----------------------------------------------------------------------
  4700.  
  4701. Q-26. I can't run the Gopher server or client because...
  4702.  
  4703. Q. It won't let me see files that I'm sure I've put in the
  4704.    ACCESS file.  Or other random garbage.  Or not seeing CR/LF's.
  4705.  
  4706. A. There could be a problem with ASCII-EBCDIC translation.
  4707.    Or you could be communicating with a VM/CMS Gopher that has problems
  4708.    talking to MVS because of problems with the ASCII/EBCDIC translation
  4709.    at their end.  For example, CMS Gopher prior to version 2.4.  If so,
  4710.    make sure that the site in question gets a new CMS gopher from
  4711.    troth@ricevm1.rice.edu.
  4712.  
  4713.    If you want to tweak your own translation, ask Doron Shikmoni
  4714.    <P85025@BARILVM.BITNET> about usermods to the TCP/IP translate tables.
  4715.  
  4716.    Also keep in mind that with MVS Gopher V3, you must stop and
  4717.    restart your Gopher server whenever you make a change to the
  4718.    access file.  And, since the access file is processed quite
  4719.    differently from the way it was in V2, you should reread the
  4720.    description of the access rule processing and make sure that
  4721.    you understand what it is doing.
  4722.  
  4723. ----------------------------------------------------------------------
  4724.  
  4725. Q-27. I get an 0C1 ABEND when I try to run the server/client
  4726.    right after I linkedited it.
  4727.  
  4728. A. Possibilities:
  4729.  
  4730.    Could be you don't have the C runtime library present in the system
  4731.    link list or STEPLIB.  This could apply to C/370 or SAS/C.  For the
  4732.    client, you can do this via ISPLLIB or LIBDEF (but see Q-17).  For
  4733.    the server, you can use STEPLIB.  But the best answer is to pester
  4734.    your MVS systems programmer to put the C runtimes in linklist.
  4735.  
  4736. ----------------------------------------------------------------------
  4737.  
  4738. Q-28. I can't figure out how to define the main Gopher menu to the server.
  4739.  
  4740. A. In the Gopher server JCL, there's a DD statement for DDname
  4741.    GGGOPHER.  This has to point to a sequential data set (or a member
  4742.    of a PDS) containing an MVS Gopher menu.  You could also specify the
  4743.    main menu (again in the MVS Gopher menu format) as instream (DD *)
  4744.    data - if you were running the Gopher server from a batch job, which
  4745.    you would do only for testing.
  4746.  
  4747. ----------------------------------------------------------------------
  4748.  
  4749. Q-29. Why doesn't the Gopher client honor my additional parameters,
  4750.    like when I type SERVER(blah)?
  4751.  
  4752. A. Did you set up your GOPHER exec to use a different ISPF APPLID?
  4753.    There is a misfeature in Gopher V1 and V2 that results from
  4754.    the use of the ISPF profile pool to pass values from the GOPHER
  4755.    command to the client load module.  Gopher V3 finally solved this
  4756.    problem by using an in-storage temporary ISPF table to pass the
  4757.    values around.
  4758.  
  4759.    To get around this in V2, stop using the APPLID, or use an APPLID of
  4760.    ISR.  Or always invoke GOPHER from inside ISPF, rather than typing
  4761.    the command from READY mode.
  4762.  
  4763. ----------------------------------------------------------------------
  4764.  
  4765. Q-30. Why can't I attention out of the Gopher client?
  4766.  
  4767. A. Because IBM C/370 is broken.  There is a zap for the IBMBLIIA
  4768.    load module that will at least let you attention out of the
  4769.    C/370 Gopher client.  It won't allow you to abort a single
  4770.    connection/transfer, though.  This didn't happen when we were
  4771.    all writing applications in 370 assembler language...
  4772.  
  4773.    Here's the zap for C/370 V2...
  4774.  
  4775.    NAME IBMBLIIA IBMBLII1
  4776.    VER 2250 0A60
  4777.    REP 2250 1BFF
  4778.  
  4779.    Usual disclaimers apply.
  4780.  
  4781.    Note:  If your edition of IBMBLIIA doesn't match, then look for
  4782.    the 0A60 (SVC 96, STAX) macro invocation that gets passed a
  4783.    nonzero register 1 value, and zap it as above.
  4784.  
  4785. ----------------------------------------------------------------------
  4786.  
  4787. Q-31. Why do I have to "S" (select) an item before I can "E" (extract) it?
  4788.  
  4789. A. This was fixed in V2R3, which should be out by the
  4790.    time you've caught up with all your real work and get around to
  4791.    reading this FAQ in your spare time.
  4792.  
  4793. ----------------------------------------------------------------------
  4794.  
  4795. Q-32. Where's the tutorial?
  4796.  
  4797. A. What tutorial? :-)
  4798.  
  4799.    Use the "About This Gopher" item to find out about using
  4800.    the Gopher client.  OK, this isn't much of an answer, but
  4801.    isn't Gopher a much more pleasant way to read stuff than
  4802.    ISPF tutorial panels?  Also, there's a TSO HELP member.
  4803.  
  4804. ----------------------------------------------------------------------
  4805.  
  4806. Q-33. What's the deal with the "w" type?
  4807.  
  4808. A. The "w" (WHOIS) type was put in to handle WHOIS-type
  4809.    applications, which are like type 7 (index) except that
  4810.    they return a file instead of a directory.  This type was
  4811.    proposed early on and implemented in the UMn Unix Gopher
  4812.    via a patch, but nowhere else.  Even the implementations
  4813.    of "w" in UMn and the MVS Gopher didn't agree with each other.
  4814.    The "w" type died out of lack of interest and the general
  4815.    belief that gopher+ would handle the same needs.  Well,
  4816.    gopher+ is still a ways away for the MVS gopher...
  4817.  
  4818.    Keener eyes among you will claim to notice gopher+ support
  4819.    in the V3 MVS gopher.  It's only the groundwork for possible
  4820.    future support.  No promises.  Let me just say that if a
  4821.    gopher+ client talks to the MVS Gopher server, it might get
  4822.    a little more than the V2 Gopher server would have given it.
  4823.  
  4824. ----------------------------------------------------------------------
  4825.  
  4826. Q-34. How can I debug a Gopher server REXX exec?
  4827.  
  4828. A. It ain't easy.  The easiest thing is just to run the exec from
  4829.    TSO and see what it does, after allocating file SYSTSPRT to
  4830.    the terminal (or wherever).  Remember, in V2, your exec must be
  4831.    writing to SYSTSPRT to return data to the Gopher server.
  4832.    But in V3 your exec uses a different means of returning data.
  4833.    You must be sure to include the REXX library with all the
  4834.    gopher-related execs if you try to test it out at your terminal.
  4835.    Best thing is to allocate this same library to SYSEXEC.  At least
  4836.    with V3, if anything bad happens, it will try to write to the real
  4837.    terminal in foreground, and to the file SYSTSPRT in background.
  4838.    And since SYSTSPRT will not be swallowed up by Gopher, you might
  4839.    actually be able to view it if you include an appropriate DD
  4840.    statement in your proc.  But don't do that unless you're running
  4841.    the single-tasking server, please.
  4842.  
  4843.    At least the Gopher server log displays return codes from IRXEXEC.
  4844.    Return codes from IRXEXEC are documented in the TSO/E REXX
  4845.    Reference.  Error codes in the range 20000-20099 indicate
  4846.    that the REXX interpreter detected a syntax error.  The return
  4847.    code is 20000 plus the error (presumably the Cowlishaw error number).
  4848.  
  4849.    Another possibility is to run the exec from your MVS Gopher client
  4850.    in "local" (serverless) mode.  Allocate your Gopher REXX exec
  4851.    library to dd GGEXEC (or use the specification in the GOPHERRC file)
  4852.    and specify HOST=- to fire it up.  If you are using V2 or earlier,
  4853.    make sure that the hacks used to specify the hostname and port are
  4854.    appropriate (i.e. they return "-" and "70").
  4855.  
  4856. ----------------------------------------------------------------------
  4857.  
  4858. Q-35. What hostname and port hacks?
  4859.  
  4860. A. Er, see the "About this Gopher" PDS for details.  I confess
  4861.    that the REXX stuff was complicated and difficult to handle.
  4862.    But with V3, it has been redesigned (incompatibly) to make it
  4863.    somewhat easier, if still complicated.  In any case, you can
  4864.    use the sample TSOHELP application as a starting point.
  4865.  
  4866. ----------------------------------------------------------------------
  4867.  
  4868. Q-36. What MVS file types does the Gopher server support?
  4869.  
  4870. A. The Gopher server can serve MVS sequential data sets and
  4871.    PDS members.  It will also serve PDS's, treating them as
  4872.    Gopher directories of members - but this is of limited use,
  4873.    as it will display merely the 8-character member names as
  4874.    Gopher files.
  4875.  
  4876.    In addition, the Gopher server recognizes exec:foo as a
  4877.    call to a REXX exec called foo, and ftp0: and ftp1: as
  4878.    invocations of a Gopher-to-FTP gateway (ftp0 to get a
  4879.    remote file, ftp1 to get a remote directory).
  4880.  
  4881.    With V3, Gopher also supports other file types, including
  4882.    binary data.  This is mainly useful for the FTP gateway,
  4883.    though it does not support compressed files.  Also, the MVS
  4884.    client can obviously do very little with binary or graphical
  4885.    or sound files.  The feature will prove highly beneficial for
  4886.    clients on other machines that talk to the MVS server.  I have
  4887.    even pulled down a newer version of the Macintosh TurboGopher
  4888.    client through the MVS gopher ftp gateway.
  4889.  
  4890.    Gopher will not support other MVS file types directly, but
  4891.    you can code a REXX exec to access such files (e.g. VSAM
  4892.    data sets or DB2 data bases).
  4893.  
  4894. ----------------------------------------------------------------------
  4895.  
  4896. Q-37: How can I display square brackets while viewing text?
  4897.  
  4898. A: By issuing the following command once in ISPF:
  4899.  
  4900. For a 3179:
  4901.  
  4902.  TERM CHAR((X'BA' X'AD') (X'BB' X'BD') (X'AD' X'BA') (X'BD' X'BB'))
  4903.  
  4904. For a 3278 or 3180:
  4905.  
  4906.  TERM CHAR((X'41' X'AD') (X'42' X'BD') (X'AD' X'41') (X'BD' X'42'))
  4907.  
  4908. If what you're seeing instead of brackets are vowels with diaeresis
  4909. marks on them, then you are in TN3270, on a 7171, or using a terminal
  4910. type of "APL" - otherwise the brackets would be being translated to
  4911. something incorrect.  So you've got half the job done, since the code
  4912. points are right.  The other half is to issue that TERMINAL command.
  4913. You can't do it from READY because as soon as ISPF starts up, it will
  4914. trash any VTAM character translations you did before.
  4915.  
  4916. If, on the other hand, you're seeing dots, or whatever the "DISP"
  4917. character is set to, then you need a fix to ISPF.  You can get the
  4918. package that implements the fix by ftp from ftp.mic.ucla.edu, directory
  4919. /pub/mvs/util, item BRACKETS.
  4920.  
  4921. ----------------------------------------------------------------------
  4922.  
  4923. Q-38: How can I make the client start up at a specific bookmark file?
  4924.  
  4925. A: Just changing the GOPHERRC file to point to the bookmark dataset
  4926.    that has the right menu won't work too well, unless you specify the
  4927.    LOCAL option when you start up gopher.  But you don't want to do
  4928.    this - I will explain.
  4929.  
  4930. Also, changing the gopher exec is the wrong thing to do.  You should
  4931. be able to change only the gopherrc file and still have it do what you
  4932. want it to do.
  4933.  
  4934. Did you set localmenu in the read_gopherrc routine?  If you didn't,
  4935. then it gets cleared before gopherrc is read.  I tried this, setting
  4936. localmenu in the read_gopherrc routine, and it works for me.  This is
  4937. not the right approach, though.  And there is another problem.
  4938. Specifying LOCAL means that your gopher cannot make any network
  4939. connections, which is not going to make it very useful.
  4940.  
  4941. Bookmark support is fairly new, and I do not yet have a good way of
  4942. having your gopherrc file set you up easily to reference a particular
  4943. bookmark.  This will take some additional documentation or fixing of
  4944. the code.  Meanwhile, here is what to do:
  4945.  
  4946. In the gopherrc file, when it is first created, you will see a section
  4947. that says
  4948.  
  4949. initial:
  4950. #
  4951. Type=DIRECTORY
  4952. Name=primary (root) gopher menu (or something like that)
  4953. Path=
  4954. Host=mvs.localdomainname.com
  4955. Port=70
  4956. End
  4957.  
  4958. Change the above so that Name= reads whatever you want the title to
  4959. display, Path= contains the fully qualified (but without single quotes)
  4960. name of your bookmark file, and (most important to remember this)
  4961. Host=- (hyphen).  If you do not change the host=, then you will get an
  4962. error from the gopher server, who will complain that it is not
  4963. authorized to deliver the contents of that directory to your doorstep.
  4964. Host=- insures that the operation on that menu alone is "local" - do
  4965. not specify the LOCAL operand on your gopher invocation.
  4966.  
  4967. ----------------------------------------------------------------------
  4968.  
  4969. Q-39: Can I set up client items that do anything my users would want?
  4970.  
  4971. A: Well, er, you're not supposed to, but - yeah, you can.
  4972.    Using a combination of HOST=- (local-mode menu items), private menus
  4973.    (bookmarks or gopherrc file hacking) and the EXEC:rexxexecname path
  4974.    syntax, you can set up a private gopher that lets you do anything
  4975.    you want.  Read the "Using Gopher on MVS" stuff in "About This Gopher",
  4976.    as well as the HELP file (operand LOCAL).
  4977.  
  4978. ./ ENDUP
  4979. ?!
  4980. //CLIST    EXEC MDLOAD,BS='6160',TRK1='5',TRK2='1',TO='CLIST'
  4981. //SYSIN    DD   DATA,DLM='?!'
  4982. ./ ADD NAME=GCALL
  4983. /* REXX.  Usage: call gcall "MODULE", "parameter list"
  4984.  *        Replaces TSO "CALL" command.
  4985.  *        Module must be in linklist or steplib.
  4986.  */
  4987.  
  4988. parse arg gmodule, gparam
  4989.  
  4990. linklen = d2c(length(gparam),2)
  4991. linkparm = linklen || gparam
  4992.  
  4993. address LINKPGM gmodule "LINKPARM"
  4994. return rc
  4995.  
  4996. ./ ADD NAME=GCLOSE
  4997. /* REXX.  Usage:  call gclose
  4998.  * Note: we cannot use DD SYSTSPRT in a multitasking environment,
  4999.  * so do not invoke this function with a null parameter unless
  5000.  * you have no choice.
  5001.  */
  5002.  
  5003. parse arg gopherargs
  5004.  
  5005. file_to_close = gfile(gopherargs) /* defined below */
  5006.  
  5007. /* The old way, which required that the caller not queue null lines
  5008.  * queue ""
  5009.  * "EXECIO * DISKW" file_to_close "(FINIS)"
  5010.  */
  5011.  
  5012. if queued() = 0 then queue " "
  5013. "EXECIO" queued() "DISKW" file_to_close "(FINIS)"
  5014. iorc = rc
  5015.  
  5016. "delstack"
  5017.  
  5018. if iorc <> 0 then do
  5019.  call gnotify ,
  5020.      "GGMVS003 EXECIO return code" iorc "in GCLOSE of" file_to_close
  5021. end
  5022.  
  5023. return
  5024.  
  5025. gfile: parse arg gopherargs
  5026.  
  5027.  parse var gopherargs "OUTDD=" outdd ";"
  5028.  if outdd = "" then outdd = "SYSTSPRT"
  5029.  return outdd
  5030.  
  5031. ./ ADD NAME=GHOST
  5032. ghost: parse arg gopherargs
  5033.  
  5034.  /* Although it should not be necessary with the new MVS Gopher,
  5035.   * configure the default host name to match your site.
  5036.   */
  5037.  
  5038.  parse var gopherargs "HOST=" host ";"
  5039.  if host = "" then return "MVS.DRAPER.COM"
  5040.  return host
  5041.  
  5042. ./ ADD NAME=GNOTIFY
  5043. /* REXX.  Usage:  call gnotify "GGMVSnnn" message-text */
  5044.  
  5045. gnotify: parse arg message
  5046. call gcall "XGWTO", message
  5047. return
  5048.  
  5049. ./ ADD NAME=GOPEN
  5050. /* REXX.  Usage:  call gopen */
  5051.  
  5052. "newstack"
  5053.  
  5054. return
  5055.  
  5056. ./ ADD NAME=GOPHER
  5057. /* REXX. GOPHER client.  Author: Steve Bacher <seb@draper.com>, with
  5058.  *       additions by Dwight Cook <SYSDC@uokmvsa.backbone.uoknor.edu>
  5059.  */
  5060.  
  5061. /* *** Customize the following lines for your installation.
  5062.  * If ggmpanel is set to "", it will not be LIBDEF'd.
  5063.  */
  5064.  
  5065. ggmprefix        = "GOPHER"
  5066. ggmpanelsuffix   = "PANELS"
  5067. ggmloadsuffix    = "LOAD"
  5068. ggmlmod          = "GGCLIENT"
  5069. ggmpanel         = ggmprefix"."ggmpanelsuffix
  5070. ggmload          = ggmprefix"."ggmloadsuffix
  5071. ggmappl          = "ISR"
  5072. ggmdefaulthost   = "micro.umn.edu" /* initialize GOPHERRC with this  */
  5073. ggmdefaulttelnet = "TELNET"
  5074. ggmdefaultbkmgr  = "BOOKMGR"
  5075. ggmdefaultdomain = ".DRAPER.COM"
  5076. gophermeister    = ""              /* TSOid of Gopher's Big Brother  */
  5077. xprocavailable   = 0               /* set to 1 if XPROC is available */
  5078. crunlibs         = ""              /* if C run-time must be LIBDEF'd */
  5079.  
  5080. trace off
  5081. signal on novalue
  5082. stacked   = 0
  5083. libdeffed = 0
  5084. parse arg args
  5085. "ISPQRY"
  5086. if rc > 0 then do
  5087.  parse source . . execname . execds .
  5088.  if execds = "?" then
  5089.   icmd = "%"execname args
  5090.  else
  5091.   icmd = "EX '"execds"("execname")'" quote(args)
  5092.  call startispf ggmappl, icmd
  5093.  exit
  5094. end
  5095.  
  5096. if xprocavailable then do
  5097.  
  5098.  save_prompt = prompt("ON")
  5099.  "XPROC 0 TEST DEBUG FORCE LOCAL BOOKMARK() INITFILE()
  5100.           SERVER() PORT() PATH() DESCRIPTION()"
  5101.  if rc <> 0 then exit rc
  5102.  call prompt save_prompt
  5103.  
  5104. end
  5105.  
  5106. else do /* XPROC not available */
  5107.  
  5108.  bookmark = ""
  5109.  initfile = ""
  5110.  server = ""
  5111.  port = 70
  5112.  path  =
  5113.  description =
  5114.  local =
  5115.  force =
  5116.  test  =
  5117.  debug =
  5118.  uargs = translate(args)
  5119.  if wordpos("LOCAL",uargs) > 0 then local = "LOCAL"
  5120.  if wordpos("FORCE",uargs) > 0 then force = "FORCE"
  5121.  if wordpos("TEST" ,uargs) > 0 then test  = "TEST"
  5122.  if wordpos("DEBUG",uargs) > 0 then debug = "DEBUG"
  5123.  
  5124.  /* Limited-function parsing courtesy Dwight Cook */
  5125.  
  5126.  bookopen = 'BOOKMARK('
  5127.  initopen = 'INITFILE('
  5128.  servopen = 'SERVER('
  5129.  pathopen = 'PATH('
  5130.  portopen = 'PORT('
  5131.  descopen = 'DESCRIPTION('
  5132.  closparn = ')'
  5133.  parse var uargs (bookopen) bookmark    (closparn)
  5134.  parse var uargs (initopen) initfile    (closparn)
  5135.  parse var uargs (servopen) server      (closparn)
  5136.  parse var uargs (pathopen) path        (closparn)
  5137.  parse var uargs (portopen) port        (closparn)
  5138.  parse var uargs (descopen) description (closparn)
  5139.  if port = "" then port = 70
  5140.  
  5141. end
  5142.  
  5143. signal on failure
  5144. signal on halt
  5145.  
  5146. call check_for_other_socket_app
  5147. call read_gopherrc
  5148. call validate_operands
  5149. call libdef
  5150. call let_me_know
  5151. call ggm_dialog
  5152. call unlibdef
  5153.  
  5154. cleanup:
  5155. if libdeffed then call unlibdef
  5156. if stacked then "DELSTACK"
  5157. exit
  5158. error:failure:halt:say "GOPHER: Severe lossage."
  5159. say "Statement:" sourceline(sigl)
  5160. exit
  5161.  
  5162. /*********************************************************************/
  5163.  
  5164. validate_operands:
  5165.  
  5166. /*
  5167.  * Logic that determines what to display on startup:
  5168.  * If gopherrc file does not exist, create it from default
  5169.  * (default has everything commented out except for a
  5170.  *  one-item "initial" menu pointing to the MVS server)
  5171.  * Read gopherrc (in case operands need fields therein)
  5172.  * Command operands override gopherrc specs:
  5173.  * if LOCAL given then server = "-", see below for SERVER(-)
  5174.  * if SERVER(host) given then startup host=SERVER, path=PATH, etc.
  5175.  *  (no gopherrc referenced)
  5176.  * if SERVER(-) given then either PATH must be given or
  5177.  *  the gopherrc's localmenu: must be given,
  5178.  *  otherwise look at gopherrc
  5179.  *   if LOCAL given and initial: present then extract startup menu
  5180.  *    but remember that there will be no server access possible
  5181.  *   else nothing given, this is an error, barf
  5182.  * if no SERVER, look at gopherrc:
  5183.  *   if initial: given then extract startup menu from there
  5184.  *   else if localmenu: given then use that menu (SERVER=-)
  5185.  *   else nothing given, display ISPF panel asking for host/path
  5186.  */
  5187.  
  5188. if local = "LOCAL" then do
  5189.  if server <> "" then do
  5190.   say "GOPHER: SERVER cannot be specified when LOCAL is specified."
  5191.   exit 12
  5192.  end
  5193.  server = "-"
  5194. end
  5195.  
  5196. if bookmark <> "" then do
  5197.  if server <> "" & local = "" then do
  5198.   say "GOPHER: SERVER cannot be specified when BOOKMARK is specified."
  5199.   exit 12
  5200.  end
  5201.  if path <> "" then do
  5202.   say "GOPHER: PATH cannot be specified when BOOKMARK is specified."
  5203.   exit 12
  5204.  end
  5205.  server = "-"
  5206.  if left(bookmark,1) = "'" then path = strip(bookmark,"B","'")
  5207.  else do
  5208.   tsoprefix = sysvar("SYSPREF")
  5209.   if tsoprefix = "" then path = bookmark
  5210.   else path = tsoprefix"."bookmark
  5211.  end
  5212.  if description = "" then description = "Bookmark" path
  5213. end
  5214.  
  5215. ggpath = ""
  5216. gghost = ""
  5217. ggport = port
  5218. ggdesc = description
  5219.  
  5220. if server <> "" then do
  5221.  if server = "-" then do
  5222.   gghost = server
  5223.   if path <> "" then do
  5224.    ggpath = path
  5225.   end
  5226.   else if localmenu <> "" then do
  5227.    ggpath = localmenu
  5228.    if ggdesc = "" then ggdesc = "Local Private Gopher Menu"
  5229.   end
  5230.   else if local = "LOCAL" & initial <> "" then do
  5231.    gghost = ""
  5232.    call use_initial_spec
  5233.    if gghost <> "-" then do
  5234.     say "Gopher: Cannot determine path for local access."
  5235.     say "        Either specify PATH(pathname), activate"
  5236.     say "        the localmenu: line in" gopherrc ", or set"
  5237.     say "        the initial: line in" gopherrc "for local access."
  5238.     exit 12
  5239.    end
  5240.   end
  5241.   else do
  5242.    say "Gopher: Cannot determine path for local access."
  5243.    say "        Either specify PATH(pathname) or activate"
  5244.    say "        the localmenu: or initial: line in "gopherrc"."
  5245.    exit 12
  5246.   end
  5247.  end
  5248.  else do
  5249.   gghost = server
  5250.   ggpath = path
  5251.   ggdesc = description
  5252.   ggport = port
  5253.   nop  /* use provided server, host, path, etc. */
  5254.  end
  5255. end
  5256. else do       /* no server given on command */
  5257.  if localmenu <> "" then do
  5258.   gghost = "-"
  5259.   ggpath = localmenu
  5260.   if ggdesc = "" then ggdesc = "Local Private Gopher Menu"
  5261.  end
  5262.  else if initial <> "" then do
  5263.   call use_initial_spec
  5264.  end
  5265.  else do
  5266.   /* this is nominally illegal, but should cause gopher to
  5267.      display the hackish startup menu */
  5268.   gghost = ""
  5269.   ggpath = ""
  5270.  end
  5271. end
  5272.  
  5273. if telnet = "" then ggtelnet = ggmdefaulttelnet
  5274. else ggtelnet = telnet
  5275.  
  5276. if bookmgr = "" then ggbkmgr = ggmdefaultbkmgr
  5277. else ggbkmgr = bookmgr
  5278.  
  5279. if domain = "" then ggdomain = ggmdefaultdomain
  5280. else ggdomain = domain
  5281.  
  5282. return
  5283.  
  5284. /*********************************************************************/
  5285.  
  5286. use_initial_spec:
  5287.  
  5288.  if initial = "*temp*" then do
  5289.   /* we're eventually not going to do it this way really */
  5290.   /* initial_type is ignored - only "DIRECTORY" is valid anyway */
  5291.   if initial_name <> "" & ggdesc = "" then ggdesc = initial_name
  5292.   if initial_host <> "" & gghost = "" then gghost = initial_host
  5293.   if initial_path <> "" & ggpath = "" then ggpath = initial_path
  5294.   if initial_port <> "" & ggport = "" then ggport = initial_port
  5295.  end
  5296.  else do
  5297.   ggpath = initial
  5298.   if ggdesc = "" then ggdesc = "Local Private Gopher Menu"
  5299.  end
  5300.  
  5301. return
  5302.  
  5303. /*********************************************************************/
  5304.  
  5305. read_gopherrc:
  5306.  
  5307. localmenu = ""
  5308. localexec = ""
  5309. telnet    = ""
  5310. bookmgr   = ""
  5311. domain    = ""
  5312. initial   = ""
  5313. initial_type = ""
  5314. initial_name = ""
  5315. initial_host = ""
  5316. initial_path = ""
  5317. initial_port = ""
  5318. new_gopherrc = 0
  5319. if initfile = "" then gopherrc = "'"userid()".GOPHERRC'"
  5320. else gopherrc = initfile
  5321. gopherrc = "'"userid()".GOPHERRC'"
  5322. gopherdcb = "RECFM(V B) LRECL(255) BLKSIZE(6233) DSORG(PS)"
  5323. gopherrc_status = sysdsn(gopherrc)
  5324. select
  5325.  when gopherrc_status = "OK" then nop
  5326.  when gopherrc_status = "DATASET NOT FOUND" then do
  5327.   address TSO "ALLOC DA("gopherrc") T SP(1 1)" gopherdcb
  5328.   if rc <> 0 then do
  5329.    say "Error: Cannot create" gopherrc
  5330.    exit rc
  5331.   end
  5332.   new_gopherrc = 1
  5333.  end
  5334.  otherwise do
  5335.   say "Error: Cannot access" gopherrc":" gopherrc_status
  5336.   exit 16
  5337.  end
  5338. end
  5339.  
  5340. address TSO "ALLOC FI(GOPHERRC) DA("gopherrc") OLD REU"
  5341. if rc <> 0 then exit rc
  5342.  
  5343. if new_gopherrc = 0 then do
  5344.  "EXECIO * DISKR GOPHERRC (FINIS STEM GOPHERRC.)"
  5345.  execiorc = rc
  5346.  if execiorc <> 0 then do
  5347.   say "Error: Cannot read" gopherrc
  5348.   address TSO "FREE FI(GOPHERRC)"
  5349.   exit execiorc
  5350.  end
  5351.  if gopherrc.0 = 0 then new_gopherrc = 1
  5352. end
  5353.  
  5354. if new_gopherrc then call initialize_gopherrc
  5355.  
  5356. address TSO "FREE FI(GOPHERRC)"
  5357.  
  5358. collecting_initial = 0
  5359. do i = 1 to gopherrc.0
  5360.  gline = gopherrc.i
  5361.  if gline = "" then iterate
  5362.  if left(gline,1) = '#' then iterate
  5363.  parse var gline ghead ":" gtext
  5364.  ghead = translate(strip(ghead,"B"))
  5365.  gtext = strip(gtext,"B")
  5366.  if collecting_initial then do
  5367.   parse var gline ghead "=" gtext
  5368.   ghead = translate(strip(ghead,"B"))
  5369.   gtext = strip(gtext,"B")
  5370.   select
  5371.    when ghead = "TYPE" then initial_type = gtext
  5372.    when ghead = "NAME" then initial_name = gtext
  5373.    when ghead = "PATH" then initial_path = gtext
  5374.    when ghead = "HOST" then initial_host = gtext
  5375.    when ghead = "PORT" then initial_port = gtext
  5376.    when ghead = "END"  then do
  5377.     collecting_initial = 0
  5378.     initial = "*temp*"
  5379.    end
  5380.    otherwise do
  5381.     say "Error in "gopherrc": INITIAL: not terminated by END"
  5382.     say "Line where error was detected:"
  5383.     say gline
  5384.     exit 8
  5385.    end
  5386.   end
  5387.  end
  5388.  else select
  5389.   when ghead = "LOCALMENU"   then localmenu = gtext
  5390.   when ghead = "LOCALEXEC"   then localexec = gtext
  5391.   when ghead = "TELNET"      then telnet    = gtext
  5392.   when ghead = "BOOKMGR"     then bookmgr   = gtext
  5393.   when ghead = "DOMAIN"      then domain    = gtext
  5394.   when ghead = "INITIAL"     then do
  5395.    if gtext = "" then collecting_initial = 1
  5396.    else initial = gtext
  5397.   end
  5398.   otherwise do
  5399.    say "Warning, gopherrc field ignored:" ghead
  5400.   end
  5401.  end
  5402. end
  5403.  
  5404. return
  5405.  
  5406. /*********************************************************************/
  5407.  
  5408. ggm_dialog:
  5409.  
  5410. tbputvars = "GGHOST GGPORT GGPATH GGDESC GGDOMAIN GGTELNET GGBKMGR"
  5411.  
  5412. address ISPEXEC "TBCREATE GOPHERVT NAMES("tbputvars") NOWRITE REPLACE"
  5413. if rc > 4 then do; call ispf_error rc; exit rc; end
  5414. address ISPEXEC "TBADD GOPHERVT"
  5415. if rc > 8 then do; call ispf_error rc; exit rc; end
  5416.  
  5417. parm = ""
  5418. if test  = "TEST"  then parm = parm "-t"
  5419. if debug = "DEBUG" then parm = parm "-d"
  5420. if local = "LOCAL" then parm = parm "-l"
  5421. if gghost <> ""    then parm = parm "-q"
  5422.  
  5423. zerrmsg = ""
  5424. zerrsm  = ""
  5425. zerrlm  = ""
  5426.  
  5427. address ISPEXEC "VPUT (ZERRMSG ZERRSM ZERRLM)"
  5428.  
  5429. if ggmappl = "" then applsource = ""
  5430. else applsource = "NEWAPPL("ggmappl") PASSLIB"
  5431.  
  5432. if ggmload = "" then selstring = "PGM("ggmlmod") PARM("parm")"
  5433. else selstring = "CMD(CALL '"ggmload"("ggmlmod")'" quote(parm)")"
  5434.  
  5435. address ISPEXEC "SELECT" applsource selstring
  5436.  
  5437. if rc <> 0 then say "Return code from" ggmlmod "program is" rc
  5438.  
  5439. /* Table was supposed to be closed in the program, but just in case */
  5440.  
  5441. address ISPEXEC "CONTROL ERRORS RETURN"
  5442. address ISPEXEC "TBCLOSE GOPHERVT"  /* don't bother checking rc */
  5443.  
  5444. address ISPEXEC "VGET (ZERRSM ZERRLM)"
  5445. if zerrsm <> "" then do
  5446.  say zerrmsg":" zerrsm
  5447.  say zerrlm
  5448. end
  5449.  
  5450. return
  5451.  
  5452. /*********************************************************************/
  5453.  
  5454. libdef:
  5455. if crunlibs <> "" then do
  5456.  address ISPEXEC "LIBDEF ISPLLIB DATASET ID("crunlibs")"
  5457.  if rc <> 0 then do; call ispf_error rc; exit rc; end
  5458. end
  5459. if ggmpanel <> "" then do
  5460.  address ISPEXEC "LIBDEF ISPPLIB DATASET ID('"ggmpanel"')"
  5461.  if rc <> 0 then do; call ispf_error rc; exit rc; end
  5462. end
  5463. if localexec <> "" then do
  5464.  address TSO "ALLOC FI(GGEXEC) SHR REU DA('"localexec"')"
  5465.  if rc <> 0 then exit rc
  5466. end
  5467. libdeffed = 1
  5468. return
  5469.  
  5470. /*********************************************************************/
  5471.  
  5472. unlibdef:
  5473. if localexec <> "" then do
  5474.  address TSO "FREE FI(GGEXEC)"
  5475. end
  5476. if ggmpanel <> "" then do
  5477.  address ISPEXEC "LIBDEF ISPPLIB DATASET"
  5478.  if rc <> 0 then call ispf_error rc
  5479. end
  5480. if crunlibs <> "" then do
  5481.  address ISPEXEC "LIBDEF ISPLLIB DATASET"
  5482.  if rc <> 0 then call ispf_error rc
  5483. end
  5484. libdeffed = 0
  5485. return
  5486.  
  5487. /*********************************************************************/
  5488.  
  5489. initialize_gopherrc:
  5490.  
  5491.  say "Initializing new GOPHERRC file "gopherrc"..."
  5492.  do i = sigl while sourceline(i) <> "_BEGIN_"
  5493.  end
  5494.  gx = 0
  5495.  do i = i+1 by 1
  5496.   gline = sourceline(i)
  5497.   if gline = "_END_" then leave
  5498.   gpos = pos("ggmdefaulthost",gline)
  5499.   if gpos > 0 then gline = substr(gline,1,gpos-1) || ggmdefaulthost
  5500.   gpos = pos("ggmdefaulttelnet",gline)
  5501.   if gpos > 0 then gline = substr(gline,1,gpos-1) || ggmdefaulttelnet
  5502.   gpos = pos("ggmdefaultbkmgr",gline)
  5503.   if gpos > 0 then gline = substr(gline,1,gpos-1) || ggmdefaultbkmgr
  5504.   gpos = pos("ggmdefaultdomain",gline)
  5505.   if gpos > 0 then gline = substr(gline,1,gpos-1) || ggmdefaultdomain
  5506.   gx = gx + 1
  5507.   gopherrc.gx = gline
  5508.  end
  5509.  gopherrc.0 = gx
  5510.  "EXECIO * DISKW GOPHERRC (FINIS STEM GOPHERRC.)"
  5511.  say "New GOPHERRC file initialized."
  5512.  
  5513. return
  5514.  
  5515. /*
  5516.  
  5517. _BEGIN_
  5518. #
  5519. #
  5520. # Default "gopherrc" file, created by the MVS Gopher client.
  5521. #
  5522. # Uncomment desired fields by removing the initial "# " from them.
  5523. #
  5524. # Beware - the Gopher client may update this file with bookmarks.
  5525. #          You can delete it at any time and it will be recreated
  5526. #          from the default settings, but you'll lose your bookmarks.
  5527. #
  5528. ######################################################################
  5529. #
  5530. # If you want local (serverless) gopher access, then use the following
  5531. # lines, specifying full qualified (no quotes) data set names:
  5532. #
  5533. # localmenu: name_of_initial_gopher_menu
  5534. # localexec: name_of_pds_of_rexx_execs
  5535. #
  5536. # Specifying localmenu: is equivalent to specifying an initial: section
  5537. # with host set to "-" and path set to the value of localmenu.
  5538. #
  5539. # You cannot use your own REXX execs, however, unless you specify
  5540. # localexec: as above.  You don't need one to use the other, though.
  5541. #
  5542. ######################################################################
  5543. #
  5544. # The following is used by the Gopher client at startup to determine
  5545. # how the initial menu will appear.
  5546. #
  5547. # You may want to change the host to the one appropriate for your site.
  5548. #
  5549. initial:
  5550. #
  5551. Type=DIRECTORY
  5552. Name=Primary (Root) Gopher Menu
  5553. Path=
  5554. Host=ggmdefaulthost
  5555. Port=70
  5556. End
  5557. #
  5558. # Alternatively, if you want your own private Gopher data:
  5559. #
  5560. # initial:
  5561. #
  5562. # Type=0
  5563. # Name=My Own Private Gopherhole
  5564. # Path=userid.GOPHER.MENU
  5565. # Host=-
  5566. # End
  5567. #
  5568. # In which case you should create a data set called userid.GOPHER.MENU
  5569. # (or whatever name you choose that appears in the "Path=" line above)
  5570. # that looks like this.  (NOT in the gopherrc file!)
  5571. #
  5572. #
  5573. # gopher_menu
  5574. #
  5575. # TYPE=DIRECTORY
  5576. # NAME=Public GOPHER Server at ggmdefaulthost
  5577. # PATH=
  5578. # HOST=ggmdefaulthost
  5579. # END
  5580. #
  5581. # TYPE=DIRECTORY
  5582. # NAME=Private GOPHER
  5583. # PATH=userid.ANOTHER.GOPHER.MENU
  5584. # HOST=-
  5585. # END
  5586. #
  5587. # and then you need yet another menu, similar in format to this one,
  5588. # in userid.ANOTHER.GOPHER.MENU.  Get the idea?
  5589. #
  5590. ######################################################################
  5591. #
  5592. # These fields are used by the Gopher client to set defaults.
  5593. #
  5594. Telnet: ggmdefaulttelnet
  5595. Bookmgr: ggmdefaultbkmgr
  5596. Domain: ggmdefaultdomain
  5597. #
  5598. ######################################################################
  5599. _END_
  5600.  
  5601. */
  5602.  
  5603. /*********************************************************************/
  5604.  
  5605. check_for_other_socket_app:
  5606.  
  5607.  if local = "LOCAL" then return
  5608.  
  5609.  call nnmfiucv      /* FIND IUCVMULT in another PIE MultiTSO session */
  5610.  
  5611.  if result = 0 then return
  5612.  
  5613.  say,
  5614.  "A TCP/IP socket application appears active in another PIE session."
  5615.  if force = "FORCE" then do
  5616.   say "Proceeding anyhow, because you said FORCE."
  5617.   return
  5618.  end
  5619.  say "To proceed at this point would be potentially disastrous."
  5620.  say "If you want to use GOPHER anyway, use one of these operands:"
  5621.  say "  FORCE  -  if I'm mistaken and it's really safe to make a"
  5622.  say "            TCP/IP connection."
  5623.  say "  LOCAL  -  if you just want local (serverless) access."
  5624.  say "Terminating."
  5625.  
  5626. exit 16
  5627.  
  5628. /*********************************************************************/
  5629.  
  5630. ispf_error: parse arg ispfrc
  5631.  
  5632. say "GOPHER: ISPF dialog service error detected on line" sigl
  5633. say sourceline(sigl)
  5634. say
  5635. say zerrmsg":" zerrsm
  5636. say zerrlm
  5637. say
  5638. say "Return code =" ispfrc
  5639. say
  5640.  
  5641. return ispfrc
  5642.  
  5643. /*********************************************************************/
  5644.  
  5645. /*
  5646.  * The following function starts ISPF from READY mode.
  5647.  * Beware:  splitting the screen starts up an identical copy of the
  5648.  *          application, which may not be desirable.
  5649.  */
  5650.  
  5651. startispf: parse arg startappl, startcmd
  5652. if startappl = "" then,
  5653.  "ISPSTART CMD("startcmd")"
  5654. else,
  5655.  "ISPSTART NEWAPPL("startappl") CMD("startcmd")"
  5656. return
  5657.  
  5658. /* The following function implements Big Brother mode. */
  5659.  
  5660. let_me_know:
  5661. if gophermeister = "" | gophermeister = userid() then return
  5662. parse source . . execname . execds .
  5663. call outtrap "X."
  5664. address TSO,
  5665.  "SEND" quote(execds"("execname")" date("U") time()" "),
  5666.         "U("gophermeister") LOGON"
  5667. call outtrap "OFF"
  5668. return
  5669.  
  5670. /* The following function enquotes a string. */
  5671.  
  5672. quote: parse arg string
  5673. ix = 1
  5674. do forever
  5675.  ix = pos("'",string,ix)
  5676.  if ix = 0 then return "'"string"'"
  5677.  string = insert("'",string,ix)
  5678.  ix=ix+2
  5679. end
  5680.  
  5681. ./ ADD NAME=GPORT
  5682. gport: parse arg gopherargs
  5683.  
  5684.  /* Although it should not be necessary with the new MVS Gopher,
  5685.   * configure the default port number to match your site.
  5686.   */
  5687.  
  5688.  parse var gopherargs "PORT=" port ";"
  5689.  if port = "" then return "1570"
  5690.  return port
  5691.  
  5692. ./ ADD NAME=GRAB
  5693. /* GRAB: Gopher REXX Allocator in Batch
  5694.  *       Usage: ddname = grab(dsname,disp{,ddname})
  5695.  */
  5696. trace off
  5697. signal on novalue
  5698.  
  5699. parse arg dsname, disp, ddname
  5700. dsname = strip(dsname,"B")
  5701. disp   = strip(disp  ,"B")
  5702. ddname = strip(ddname,"B")
  5703. msg1   = ""
  5704. msg2   = ""
  5705.  
  5706. dsname = strip(dsname,"B","'")
  5707.  
  5708. do forever
  5709.  address linkmvs "XGALLOC DSNAME DDNAME DISP MSG1 MSG2"
  5710.  if rc <> 0 then do
  5711.   if pos(" IN USE",msg1) > 0 | pos(" IN USE",msg2) > 0 then do
  5712.    call gsleep 2
  5713.    iterate
  5714.   end
  5715.   if msg1 <> "" then call gnotify "GGMVS004" msg1
  5716.   if msg2 <> "" then call gnotify "GGMVS005" msg2
  5717.  end
  5718.  leave
  5719. end
  5720. return ddname
  5721.  
  5722. gsleep: parse arg seconds
  5723. call gnotify "GGMVS008" ,
  5724.      "GRAB:" dsname "in use.  Retrying in" seconds "seconds..."
  5725. call gcall "XGSLEEP", seconds
  5726. return
  5727. ./ ADD NAME=GRABTEMP
  5728. /* GRAB: Gopher REXX Allocator in Batch to Touch Empty Memory Pages
  5729.  *       Usage: ddname = grabtemp({ddname})
  5730. */
  5731. trace off
  5732. signal on novalue
  5733.  
  5734. parse arg ddname
  5735.  
  5736. dsname = ""
  5737. disp   = "NEW"
  5738. ddname = strip(ddname,"B")
  5739. msg1   = ""
  5740. msg2   = ""
  5741.  
  5742. address linkmvs "XGALLOC DSNAME DDNAME DISP MSG1 MSG2"
  5743. if rc <> 0 then do
  5744.  if msg1 <> "" then call gnotify "GGMVS004" msg1
  5745.  if msg2 <> "" then call gnotify "GGMVS005" msg2
  5746. end
  5747. return ddname
  5748. ./ ADD NAME=GREAD
  5749. /* REXX.  Usage:  call gread ddname
  5750.  */
  5751.  
  5752. parse arg ddname
  5753.  
  5754. line. =
  5755. line.0 =
  5756.  
  5757. "EXECIO * DISKR" ddname "(FINIS STEM LINE.)"
  5758.  
  5759. do i = 1 to line.0
  5760.  if line.i = "" then queue " "; else queue line.i
  5761. end
  5762.  
  5763. return
  5764.  
  5765. ./ ADD NAME=GTSOTRAP
  5766. /* REXX */
  5767.  
  5768. parse arg tsocommand, gopherargs
  5769.  
  5770. x = outtrap("LINE.")
  5771. address TSO tsocommand
  5772. arc = rc
  5773. x = outtrap("OFF")
  5774. call gopen gopherargs
  5775. do i = 1 to line.0
  5776.  if line.i = "" then queue " ";else queue line.i
  5777. end
  5778. call gclose gopherargs
  5779.  
  5780. return arc
  5781. ./ ADD NAME=HOSTNAME
  5782. /* REXX */
  5783.  
  5784. parse arg gopherargs
  5785.  
  5786. return ghost(gopherargs)
  5787.  
  5788. ./ ADD NAME=NNMFIUCV
  5789. /* REXX.  This exec scans the job pack queues for IUCVMULT and returns
  5790.  * with an error code if IUCVMULT is already loaded under a
  5791.  * different TCB. This can only happen under PIE MultiTSO or a
  5792.  * similar product that makes multiple job step TCB's.
  5793.  */
  5794.  
  5795. trace off
  5796. signal on novalue
  5797.  
  5798. search_name = "IUCVMULT"
  5799. count = 0
  5800. foundtcb. = ""
  5801. current_tcb  = getword24("21C")
  5802. current_job_step_tcb = getword24(current_tcb,"7C")
  5803. current_ascb = getword24("224")
  5804. current_asxb = getword31(current_ascb,"6C")
  5805. first_tcb    = getword24(current_asxb,"4")
  5806. tcb = first_tcb
  5807. motherflag = 0
  5808. do forever
  5809.  if motherflag = 0 then do
  5810.   call process
  5811.   daughter_tcb = getword24(tcb,"88")
  5812.   if daughter_tcb \= "00000000" then do
  5813.    tcb = daughter_tcb
  5814.    iterate
  5815.   end
  5816.  end
  5817.  motherflag = 0
  5818.  sister_tcb = getword24(tcb, "80")
  5819.  if sister_tcb \= "00000000" then do
  5820.   tcb = sister_tcb
  5821.   iterate
  5822.  end
  5823.  mother_tcb = getword24(tcb, "84")
  5824.  if mother_tcb \= "00000000" then do
  5825.   tcb = mother_tcb
  5826.   motherflag = 1
  5827.   iterate
  5828.  end
  5829.  leave
  5830. end
  5831.  
  5832. if count = 0 then return 0
  5833. problem = 0
  5834. do i = 1 to count
  5835.  if foundtcb.i = current_job_step_tcb then do
  5836.   /*
  5837.   say search_name "is already loaded under current TCB at "foundtcb.i"."
  5838.   */
  5839.  end
  5840.  else do
  5841.   /*
  5842.   say search_name "is loaded under different TCB at "foundtcb.i"."
  5843.   */
  5844.   problem = 1
  5845.  end
  5846. end
  5847.  
  5848. if problem = 1 then return 1
  5849.  
  5850. else return 0
  5851.  
  5852. process:
  5853.  
  5854.  jpq = getword31(tcb,"2C")
  5855.  cde = jpq
  5856.  do while cde \= "00000000"
  5857.   cde_contents = storage(cde,32)
  5858.   cde_name = substr(cde_contents,9,8)
  5859.   cde_epa  = substr(cde_contents,9,8)
  5860.   if search_name = cde_name then do
  5861.    count = count + 1
  5862.    foundtcb.count = tcb
  5863.   end
  5864.   cde = getword31(cde,"0")
  5865.  end
  5866.  
  5867. return
  5868.  
  5869. getword31: parse arg addr, offset
  5870. temp1 = x2d(addr)
  5871. if offset = "" then temp2 = 0
  5872. else temp2 = x2d(offset)
  5873. return c2x(storage(d2x(temp1+temp2),4))
  5874.  
  5875. getword24: parse arg addr, offset
  5876. temp1 = x2d(addr)
  5877. if offset = "" then temp2 = 0
  5878. else temp2 = x2d(offset)
  5879. return "00"c2x(storage(d2x(temp1+temp2+1),3))
  5880.  
  5881. ./ ADD NAME=PORT
  5882. /* REXX */
  5883.  
  5884. parse arg gopherargs
  5885.  
  5886. return gport(gopherargs)
  5887.  
  5888. ./ ADD NAME=REXXTEST
  5889. /* REXX */
  5890.  
  5891. parse arg args, gopherargs
  5892. parse version rexx_version
  5893. parse source rexx_source
  5894.  
  5895. call gopen gopherargs
  5896.  
  5897. queue "PARSE VERSION returns:" rexx_version
  5898. queue "PARSE SOURCE  returns:" rexx_source
  5899. queue "Argument 1 is........." args
  5900. queue "Gopherargs are........" gopherargs
  5901.  
  5902. call gclose gopherargs
  5903.  
  5904. return
  5905.  
  5906. ./ ADD NAME=TSOHELP
  5907. /* REXX */
  5908.  
  5909. /* This exec provides a sample TSO HELP application.
  5910.    The gopher menu item will look something like this:
  5911.  
  5912. TYPE=DIRECTORY
  5913. NAME=TSO HELP
  5914. PATH=EXEC:TSOHELP
  5915. HOST=+
  5916. END
  5917.  
  5918. where "TSOHELP" is the name of this exec.
  5919.  
  5920. This exec generates a series of lower-level menus, giving the user
  5921. a choice of how much help data to search (IBM only, local installation
  5922. help, etc.).  This particular sample is Draper Lab's own, so you will
  5923. need to change it.
  5924.  
  5925.  */
  5926.  
  5927. trace off
  5928. signal on novalue
  5929.  
  5930. host = hostname()
  5931. port = "70"
  5932. tab  = '05'x
  5933.  
  5934. helpfiles.        = "'SYS1.HELP'"
  5935. helpfiles.sys1    = "'SYS1.HELP'"
  5936. helpfiles.draper  = "'CSD.CMD.HELP' 'CSD.PP.HELP' 'SYS1.HELP'"
  5937. helpfiles.proglib = "'PROGLIB.CMD.HELP'"
  5938.  
  5939. parse arg helplib command type extra
  5940.  
  5941. if helplib = "" then,
  5942.      call display_top_menus
  5943. else call set_up_help helplib,command,type,extra
  5944.  
  5945. return 0
  5946.  
  5947. /*------------------------------------------------------------------*/
  5948.  
  5949. display_top_menus:
  5950.  
  5951.  call start_output
  5952.  call menu_out "SYS1",  "COMMANDS","DIRECTORY","Regular IBM TSO Help"
  5953.  call menu_out "DRAPER","COMMANDS","DIRECTORY","IBM and Draper TSO Help"
  5954.  call menu_out "PROGLIB","PROGLIB" ,"DIRECTORY","PROGLIB TSO Help"
  5955.  call end_output
  5956.  
  5957. return
  5958.  
  5959. /*------------------------------------------------------------------*/
  5960.  
  5961. set_up_help:  parse arg helplib,command,type,extra
  5962.  
  5963.  call outtrap "TSO."
  5964.  "ALLOC FI(SYSHELP) SHR REU DA("helpfiles.helplib")"
  5965.  allocrc = rc
  5966.  call outtrap "OFF"
  5967.  if allocrc <> 0 then do
  5968.   call start_output
  5969.   do i = 1 to tso.0
  5970.    call menu_out "ERROR","ERROR","DIRECTORY",tso.i
  5971.   end
  5972.   call end_output
  5973.  end
  5974.  else do
  5975.   select
  5976.    when type = "FILE"      then call specific_help command,extra
  5977.    when type = "DIRECTORY" then call general_help  command,extra
  5978.    when type = "INDEX"     then call index_help    extra
  5979.    otherwise                    call specific_help command
  5980.  end
  5981.  
  5982. return
  5983.  
  5984. /*------------------------------------------------------------------*/
  5985.  
  5986. index_help:
  5987.  
  5988.  /* This intermediate one-element directory is necessary because
  5989.   * the Gopher INDEX format only returns directories, not files.
  5990.   */
  5991.  
  5992.  parse upper arg commands
  5993.  call start_output
  5994.  do while commands <> ""
  5995.   parse var commands command commands
  5996.   call menu_out helplib,command,"FILE","Complete help for" command
  5997.   call menu_out helplib,command,"FILE","Function help only","FUNCTION"
  5998.   call menu_out helplib,command,"FILE","Syntax help only","SYNTAX"
  5999.   call menu_out helplib,command,"FILE","Operands help only","OPERANDS"
  6000.  end
  6001.  call end_output
  6002.  
  6003. return
  6004.  
  6005. /*------------------------------------------------------------------*/
  6006.  
  6007. general_help:
  6008.  
  6009. parse arg command,extra
  6010.  
  6011. call get_help_text command,extra
  6012.  
  6013. call start_output
  6014.  
  6015. call menu_out helplib,"*","INDEX","Help for a specific TSO command"
  6016.  
  6017. do i = 1 to help.0
  6018.  parse var help.i helpname helpdesc
  6019.  if helpdesc <> "" & ,
  6020.     length(helpname) <= 8 & ,
  6021.     helpname < "0" & ,
  6022.     verify(helpname,"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789W#$") = 0 ,
  6023.     then do
  6024.  
  6025.   /*
  6026.    * Draper help has a series of "$..." members which are like
  6027.    * sublevel COMMANDS members.  This hack supports that.
  6028.    */
  6029.  
  6030.   if left(helpname,1) = "$" then do
  6031.    call menu_out helplib,helpname,"DIRECTORY",helpdesc
  6032.   end
  6033.   else do
  6034.    call menu_out helplib,helpname,"FILE",helpdesc
  6035.   end
  6036.  end
  6037. end
  6038.  
  6039. call end_output
  6040.  
  6041. return
  6042.  
  6043. /*------------------------------------------------------------------*/
  6044.  
  6045. specific_help:
  6046.  
  6047. parse arg command,extra
  6048.  
  6049. call get_help_text command,extra
  6050.  
  6051. call start_output
  6052.  
  6053. do i = 1 to help.0
  6054.  call text_output help.i
  6055. end
  6056.  
  6057. call end_output
  6058.  
  6059. return
  6060.  
  6061. /*------------------------------------------------------------------*/
  6062.  
  6063. get_help_text:
  6064.  
  6065. parse arg helpcmd,helpargs
  6066.  
  6067. help. =
  6068.  
  6069. call outtrap "HELP."
  6070.  
  6071. address TSO "HELP" helpcmd helpargs
  6072.  
  6073. call outtrap "OFF"
  6074.  
  6075. return
  6076.  
  6077. /*------------------------------------------------------------------*/
  6078.  
  6079. menu_out: parse arg mlib,mname,mtype,mdesc,mops
  6080.  
  6081.  select
  6082.   when mtype = "FILE"      then gtype = "0"
  6083.   when mtype = "DIRECTORY" then gtype = "1"
  6084.   when mtype = "INDEX"     then gtype = "7"
  6085.   otherwise do
  6086.    call menu_out "ERROR","ERROR","DIRECTORY", "Unknown type:" mtype
  6087.   end
  6088.  end
  6089.  
  6090.  gname = left(mname,9)"--" mdesc
  6091.  gpath = "EXEC:TSOHELP" mlib mname mtype mops
  6092.  out = gtype || gname || tab || gpath || tab || host || tab || port
  6093.  queue out
  6094.  
  6095. return
  6096.  
  6097. /*------------------------------------------------------------------*/
  6098.  
  6099. text_output: parse arg text
  6100.  
  6101.  if text = "" then queue " "
  6102.  else queue text
  6103.  
  6104. return
  6105.  
  6106. /*------------------------------------------------------------------*/
  6107.  
  6108. start_output:
  6109.  
  6110. "newstack"
  6111.  
  6112. return
  6113.  
  6114. /*------------------------------------------------------------------*/
  6115.  
  6116. end_output:
  6117.  
  6118. queue ""
  6119.  
  6120. "EXECIO * DISKW SYSTSPRT (FINIS)"
  6121.  
  6122. "delstack"
  6123.  
  6124. return
  6125.  
  6126. ./ ADD NAME=UNGRAB
  6127. /* UNGRAB: Utterly Negate Gopher REXX Allocator in Batch
  6128.  *       Usage: call ungrab ddname {,FREE/DELETE}
  6129.  */
  6130. trace off
  6131. signal on novalue
  6132.  
  6133. parse arg ddname
  6134. dsname = ""
  6135. disp   = ""
  6136. if disp = "" then disp = "FREE"
  6137. msg1   = ""
  6138. msg2   = ""
  6139.  
  6140. address linkmvs "XGALLOC DSNAME DDNAME DISP MSG1 MSG2"
  6141. if rc <> 0 then do
  6142.  if msg1 <> "" then call gnotify "GGMVS006" msg1
  6143.  if msg2 <> "" then call gnotify "GGMVS007" msg2
  6144.  return rc
  6145. end
  6146. return 0
  6147. ./ ENDUP
  6148. ?!
  6149. //H        EXEC MDLOAD,BS='6160',TRK1='5',TRK2='1',TO='H'
  6150. //SYSIN    DD   DATA,DLM='?!'
  6151. ./ ADD NAME=GG
  6152.  
  6153.  /********************************************************************/
  6154.  /*                                                                  */
  6155.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  6156.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  6157.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  6158.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  6159.  /*                                                                  */
  6160.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  6161.  /* including the implied warranties of merchantability and fitness, */
  6162.  /* are expressly denied.                                            */
  6163.  /*                                                                  */
  6164.  /* Provided this copyright notice is included, this software may    */
  6165.  /* be freely distributed and not offered for sale.                  */
  6166.  /*                                                                  */
  6167.  /* Changes or modifications may be made and used only by the maker  */
  6168.  /* of same, and not further distributed.  Such modifications should */
  6169.  /* be mailed to the author for consideration for addition to the    */
  6170.  /* software and incorporation in subsequent releases.               */
  6171.  /*                                                                  */
  6172.  /********************************************************************/
  6173.  
  6174. /* --------------------- "gg.h" include member --------------------- */
  6175.  
  6176. #pragma linkage(ispexec,OS)
  6177. #pragma linkage(isplink,OS)
  6178. #pragma linkage(ikjeff18,OS)
  6179. #pragma linkage(ikjeftsr,OS)
  6180. #pragma linkage(irxexec,OS)
  6181. #pragma linkage(cmxlate,OS)
  6182.  
  6183. /****** Installation-customized defines. *****************************/
  6184.  
  6185. #include "gguser.h"
  6186.  
  6187. #ifndef  C370V1
  6188. #ifndef  C370V2
  6189. #ifndef  SASC
  6190.  install_error_neither_C370V1_C370V2_nor_SASC_was_defined;
  6191. #endif
  6192. #endif
  6193. #endif
  6194.  
  6195. #ifndef  TCPIPV1
  6196. #ifndef  TCPIPV2
  6197. #ifndef  SNSTCPIP
  6198.  install_error_neither_TCPIPV1_TCPIPV2_nor_SNSTCPIP_was_defined;
  6199. #endif
  6200. #endif
  6201. #endif
  6202.  
  6203. #ifndef  ISPFV2
  6204. #ifndef  ISPFV3
  6205.  install_error_neither_ISPFV2_nor_ISPFV3_was_defined;
  6206. #endif
  6207. #endif
  6208.  
  6209. #define  MVS
  6210.  
  6211. #ifdef   SNSTCPIP
  6212. #undef   USE_CMXLATE
  6213. #ifndef  I370
  6214. #define  SNSC370
  6215. #endif
  6216. #endif
  6217.  
  6218. #ifdef   I370
  6219. #undef   USE_CMXLATE
  6220. #endif
  6221.  
  6222. /****** Clean up compiler warnings BEFORE time.h gets 'em ************/
  6223.  
  6224. #ifndef  SASC
  6225. #define  localtime            LOCALTIM
  6226. #endif
  6227.  
  6228. /****** Include all header files that are necessary. *****************/
  6229.  
  6230. #ifndef SNSTCPIP
  6231. #include <manifest.h>
  6232. #include <sys/types.h>
  6233. #include <netinet/in.h>
  6234. #include <sys/ioctl.h>
  6235. #include <tcperrno.h>
  6236. #include <fcntl.h>
  6237. #endif
  6238.  
  6239. #include <sys/socket.h>
  6240. #include <netdb.h>
  6241. #include <sys/uio.h>
  6242. #include <ctype.h>
  6243. #include <errno.h>
  6244. #include <limits.h>
  6245. #include <setjmp.h>
  6246. #include <stdio.h>
  6247. #include <stdarg.h>
  6248. #include <stdlib.h>
  6249. #include <string.h>
  6250. #include <stddef.h>
  6251. #include <time.h>
  6252.  
  6253. #ifdef SNSTCPIP
  6254. #include <acs.h>
  6255. #include <inet.h>
  6256. #include <sockcfg.h>
  6257. #include <serrno.h>
  6258. #endif
  6259.  
  6260. #ifndef  SASC
  6261. #include <ctest.h>
  6262. #endif
  6263.  
  6264. #ifdef   C370V2
  6265. #undef   ENOMEM
  6266. #include <mtf.h>
  6267. #endif
  6268.  
  6269. #ifdef   SASC
  6270. #include "ggsasc.h"
  6271. #endif
  6272.  
  6273. /****** Version-dependent stuff **************************************/
  6274.  
  6275. #ifdef   C370V1
  6276. #undef   FETCH
  6277. #endif
  6278.  
  6279. #ifdef   C370V2
  6280. #define  FETCH
  6281. #endif
  6282.  
  6283. #ifdef   TCPIPV1
  6284. #define  TCP_DEBUG            tcp_debug
  6285. #endif
  6286.  
  6287. #ifdef   TCPIPV2
  6288. #define  TCP_DEBUG            sock_debug
  6289. #endif
  6290.  
  6291. #ifdef   SNSTCPIP
  6292. #define  TCP_DEBUG            /* I don't know how to debug in SNS */
  6293. #endif
  6294.  
  6295. #ifdef   GOPHER_DEBUG
  6296. #define  TCP_DEBUG_ON         TCP_DEBUG(1)
  6297. #define  TCP_DEBUG_OFF        TCP_DEBUG(0)
  6298. #else
  6299. #define  TCP_DEBUG_ON         /* */
  6300. #define  TCP_DEBUG_OFF        /* */
  6301. #endif
  6302.  
  6303. /****** Preprocessor bookkeeping *************************************/
  6304.  
  6305. #define  Bool                 char
  6306. #define  Fool                 unsigned int /* for function arguments */
  6307. #ifndef  TRUE
  6308. #define  TRUE                 1
  6309. #endif
  6310. #ifndef  FALSE
  6311. #define  FALSE                0
  6312. #endif
  6313.  
  6314. #define  GOPHER_FILE          '0'
  6315. #define  GOPHER_DIRECTORY     '1'
  6316. #define  GOPHER_MENU          '1'
  6317. #define  GOPHER_CSO           '2'
  6318. #define  GOPHER_ERROR         '3'
  6319. #define  GOPHER_MAC_BINHEX    '4'
  6320. #define  GOPHER_DOS_BINARCH   '5'
  6321. #define  GOPHER_UUENCODE      '6'
  6322. #define  GOPHER_WAIS          '7'
  6323. #define  GOPHER_INDEX         '7'
  6324. #define  GOPHER_TELNET        '8'
  6325. #define  GOPHER_TN3270        'T'
  6326. #define  GOPHER_BINARY        '9'
  6327. #define  GOPHER_REDUNDANT     '+'
  6328. #define  GOPHER_WHOIS         'w'
  6329. #define  GOPHER_IMAGE         'I'
  6330. #define  GOPHER_BOOKMANAGER   'b'
  6331. #define  GOPHER_COMMENT       'i'
  6332. #define  GOPHER_UNKNOWN       '\0'
  6333. #define  COMMANDSIZE          12
  6334. #define  INTERNET_SIZE        256
  6335. #define  RBUFSIZE             512
  6336. #define  OUTBUFSIZE           1024
  6337. #define  READ_BYTES           1024
  6338. #define  SERVER_BUF_MSGSIZE   1024
  6339. #define  CLIENT_BUF_MSGSIZE   1024
  6340. #define  TEXT_BYTES           1024
  6341. #define  GOPHER_PORT_NUMBER   70
  6342. #define  GOPHER_HOST_LENGTH   MAXHOSTNAMELEN
  6343. #define  GOPHER_PATH_LENGTH   512
  6344. #define  GOPHER_DESC_LENGTH   256
  6345. #define  SOCKET_GETCHAR_ERROR (-1)
  6346. #define  SOCKET_NO_MORE       (-2)
  6347. #define  SOCKET_READ_NOTHING  (-3)
  6348. #define  NO_VALUE             (-1)
  6349. #define  OUT_PLUS             (-2)
  6350. #define  Rstruc               register struct
  6351. #define  RGGCB                register GGCB
  6352. #define  RRECV                register RECV
  6353. #define  REXTR                register EXTRACTION
  6354. #define  RINFO                register GOPHERINFO
  6355. #define  RCONN                register CONNECTION
  6356. #define  EQUAL                !strcmp
  6357. #define  UNEQUAL              strcmp
  6358. #define  COPY(A,B)            strncpy((A),(B),sizeof(A)-1)
  6359. #define  DUMMY_FILE_POINTER   (FILE *)(-1)
  6360. #define  MAX_INT              (int)0x7fffffff
  6361. #define  LOCATE_INT           (int)0x7ffffffe
  6362. #define  CARRIAGE_RETURN      '\r'
  6363. #define  FIND_NEXT            'N'
  6364. #define  FIND_FIRST           'F'
  6365. #define  FIND_LAST            'L'
  6366. #define  FIND_PREV            'P'
  6367. #define  FIND_ALL             'A'
  6368. #define  FIND_CHARS           '\0'
  6369. #define  FIND_WORD            'W'
  6370. #define  FIND_PREFIX          'P'
  6371. #define  FIND_SUFFIX          'S'
  6372. #define  FIND_CAPS            '\0'
  6373. #define  FIND_ASIS            'A'
  6374. #define  FIND_HEX             'X'
  6375. #define  FIND_GENERIC         'P'
  6376. #define  FIND_BADFORM         '\0'
  6377. #define  FIND_UNQUOTED        'U'
  6378. #define  FIND_QUOTED          'Q'
  6379. #define  FIND_C               'C'
  6380. #define  FIND_X               'X'
  6381. #define  FIND_T               'T'
  6382. #define  FIND_P               'P'
  6383. #define  DATAOUT_LOW          0x01
  6384. #define  DATAOUT_HIGH         0x02
  6385. #define  DATAIN_LOW           0x03
  6386. #define  DATAIN_HIGH          0x04
  6387. #define  DATAOUT_BLUE         DATAOUT_LOW
  6388. #define  DATAOUT_GREEN        0x05
  6389. #define  DATAOUT_PINK         0x06
  6390. #define  DATAOUT_RED          0x07
  6391. #define  DATAOUT_TURQ         0x08
  6392. #define  DATAOUT_WHITE        DATAOUT_HIGH
  6393. #define  DATAOUT_YELLOW       0x09
  6394. #define  DATAIN_BLUE          0x0a
  6395. #define  DATAIN_GREEN         DATAIN_LOW
  6396. #define  DATAIN_PINK          0x0b
  6397. #define  DATAIN_RED           DATAIN_HIGH
  6398. #define  DATAIN_TURQ          0x0c
  6399. #define  DATAIN_WHITE         0x0d
  6400. #define  DATAIN_YELLOW        0x0e
  6401.  
  6402. #ifdef   I370
  6403. #define  LINE_FEED            0x15
  6404. #define  EtoA                 htoncs
  6405. #define  AtoE                 ntohcs
  6406. #else
  6407. #define  LINE_FEED            0x25
  6408. #ifdef   SNSTCPIP
  6409. #define  EtoA                 etoa
  6410. #define  AtoE                 atoe
  6411. #else
  6412. #define  EtoA(x)              ebcdictoascii[x]
  6413. #define  AtoE(x)              asciitoebcdic[x]
  6414. #define  ebcdictoascii        ebcdicto
  6415. #define  asciitoebcdic        asciitoe
  6416. #endif
  6417. #endif
  6418.  
  6419. #ifdef   USE_CMXLATE
  6420. #define  EBCDIC_TO_ASCII(A,B) cmxlate((A),ebcdictoascii,(B))
  6421. #define  ASCII_TO_EBCDIC(A,B) cmxlate((A),asciitoebcdic,(B))
  6422. #else
  6423. #ifdef   SNSC370
  6424. #define  EBCDIC_TO_ASCII(A,B) EtoA(A,B)
  6425. #define  ASCII_TO_EBCDIC(A,B) AtoE(A,B)
  6426. #else
  6427. #define  EBCDIC_TO_ASCII(A,B) {int _i; \
  6428.                                for (_i=0; _i<(B); ++_i) \
  6429.                                    (A)[_i] = EtoA((A)[_i]); \
  6430.                               }
  6431. #define  ASCII_TO_EBCDIC(A,B) {int _i; \
  6432.                                for (_i=0; _i<(B); ++_i) \
  6433.                                    (A)[_i] = AtoE((A)[_i]); \
  6434.                               }
  6435. #endif
  6436. #endif
  6437.  
  6438. #ifdef  TCPIPV1
  6439. #define REPORT_TCP_ERROR(A)  /* */
  6440. #endif
  6441.  
  6442. #ifdef  TCPIPV2
  6443. #define REPORT_TCP_ERROR(A)  tcperror(A)
  6444. #endif
  6445.  
  6446. #ifdef  SNSTCPIP
  6447. #define REPORT_TCP_ERROR(A)  fprintf(stderr,\
  6448.                                     "\nTCP error on %s: errno = %d\n",\
  6449.                                     A,GET_ERRNO)
  6450. #endif
  6451.  
  6452. #ifdef  SNSC370
  6453. #define Accept(A,B,C)        accept((A),(struct sockaddr *)(B),(C))
  6454. #define Bind(A,B,C)          bind((A),(struct sockaddr *)(B),(C))
  6455. #define Connect(A,B,C)       connect((A),(struct sockaddr *)(B),(C))
  6456. #define Gethostbyaddr(A,B,C) gethostbyaddr((char *)(A),(B),(C))
  6457. #define Getpeername(A,B,C)   getpeername((A),(struct sockaddr *)(B),(C))
  6458. #define Getsockname(A,B,C)   getsockname((A),(struct sockaddr *)(B),(C))
  6459. #define Getsockopt(A,B,C,D,E) getsockopt((A),(B),(C),(char *)(D),(E))
  6460. #define EWOULDBLOCK          (ESWOULDBLOCK+s0skcfg.errnobase)
  6461. #else
  6462. #define Accept               accept
  6463. #define Bind                 bind
  6464. #define Connect              connect
  6465. #define Gethostbyaddr        gethostbyaddr
  6466. #define Getpeername          getpeername
  6467. #define Getsockname(A,B,C)   getsockname((A),(char *)(B),(C))
  6468. #define Getsockopt           getsockopt
  6469. #endif
  6470.  
  6471. #ifdef  FETCH
  6472. #define ISPLINK              (gp->isplink_pointer)
  6473. #define ISPEXEC              (gp->ispexec_pointer)
  6474. #else
  6475. #define ISPLINK              isplink
  6476. #define ISPEXEC              ispexec
  6477. #endif
  6478.  
  6479. #ifdef   ISPFV3
  6480. #define  ZERRLM_SIZE          513
  6481. #else
  6482. #define  ZERRLM_SIZE          73
  6483. #endif
  6484.  
  6485. #define  GOPHER_MSGID_OK    "GGMVS001"
  6486. #define  GOPHER_MSGID_ERROR "GGMVS002"
  6487.  
  6488. #define  NOTIFY_MSG   1
  6489. #define  WARNING_MSG  2
  6490. #define  CRITICAL_MSG 3
  6491.  
  6492. #define  WARN1(X)           GGpmsg(gp,NOTIFY_MSG,NULL,X)
  6493. #define  WARN2(X,Y)         GGpmsg(gp,NOTIFY_MSG,NULL,X,Y)
  6494. #define  WARN3(X,Y,Z)       GGpmsg(gp,NOTIFY_MSG,NULL,X,Y,Z)
  6495. #define  WARN4(X,Y,Z,W)     GGpmsg(gp,NOTIFY_MSG,NULL,X,Y,Z,W)
  6496. #define  ERR1(X)            GGpmsg(gp,WARNING_MSG,NULL,X)
  6497. #define  ERR2(X,Y)          GGpmsg(gp,WARNING_MSG,NULL,X,Y)
  6498. #define  ERR3(X,Y,Z)        GGpmsg(gp,WARNING_MSG,NULL,X,Y,Z)
  6499. #define  ERR4(X,Y,Z,W)      GGpmsg(gp,WARNING_MSG,NULL,X,Y,Z,W)
  6500. #define  CRIT1(X)           GGpmsg(gp,CRITICAL_MSG,NULL,X)
  6501. #define  CRIT2(X,Y)         GGpmsg(gp,CRITICAL_MSG,NULL,X,Y)
  6502. #define  CRIT3(X,Y,Z)       GGpmsg(gp,CRITICAL_MSG,NULL,X,Y,Z)
  6503.  
  6504. #define  GETMAIN(P,T,S,F)   GGgetm(gp,(char **)&(P),(sizeof(T))*(S),F)
  6505. #define  FREEMAIN(P,F)      if (P) {GGfreem(gp,(char *)P,F);}
  6506. #define  GOPHERSEND(X,Y)    if (!(GGesrvr(X,Y),\
  6507.                                   GGsockt(X,Y))) return FALSE
  6508. #define  CLEAR(X)           memset(X,0,sizeof(*X))
  6509. #define  ISPF(X)            GGispf(gp,X)
  6510. #define  VGET(X,Y)          GGivget(gp,X,Y,sizeof(Y))
  6511. #define  VGETS(X,Y,Z)       GGivget(gp,X,Y,Z)
  6512. #define  VPUT(X,Y)          GGivput(gp,X,Y,-1)
  6513. #define  VPUTS(X,Y,Z)       GGivput(gp,X,Y,Z)
  6514. #define  IGET(X)            GGiget(gp,X)
  6515. #define  IPUT(X,Y)          {char _iput[16];\
  6516.                              sprintf(_iput,"%d",(Y));\
  6517.                              VPUT(X,_iput);}
  6518. #ifndef I370
  6519. #define  WRITE_FILEMODE     "w,recfm=vb,lrecl=259,blksize=6233"
  6520. #define  APPEND_FILEMODE    "a,recfm=vb,lrecl=259,blksize=6233"
  6521. #define  FTPTEMP_FILEMODE   "w,recfm=vb,lrecl=23444,blksize=23448"
  6522. #define  FTPBIN_FILEMODE   "wb,recfm=vb,lrecl=23444,blksize=23448"
  6523. #define  BKMGRBIN_FILEMODE "wb,recfm=fb,lrecl=4096,blksize=8192"
  6524. #define  SYSOUT_FILEMODE    "w,recfm=vba,lrecl=133"
  6525. #define  OPEN_TEXT_FILE_FOR_WRITE(F)     fopen((F),WRITE_FILEMODE)
  6526. #define  OPEN_TEXT_FILE_FOR_APPEND(F)    fopen((F),APPEND_FILEMODE)
  6527. #define  OPEN_SYSOUT_FILE(F)             fopen((F),SYSOUT_FILEMODE)
  6528. #define  OPEN_FTP_TEMP_FILE(F)           fopen((F),FTPTEMP_FILEMODE)
  6529. #define  OPEN_FTP_BINARY_FILE(F)         fopen((F),FTPBIN_FILEMODE)
  6530. #define  OPEN_BOOKMANAGER_BINARY_FILE(F) fopen((F),BKMGRBIN_FILEMODE)
  6531. #define  OPEN_TEXT_FILE_FOR_WRITE_OR_APPEND(F,B)  \
  6532.          fopen((F),(B) ? APPEND_FILEMODE : WRITE_FILEMODE)
  6533. #define  OPEN_OUTPUT_FILE_FOR_WRITE_OR_APPEND(F,B)  \
  6534.          fopen((F),(B) ? "a" : WRITE_FILEMODE)
  6535. #define  TEST_IF_FILE_EXISTS(P,F)  (P=fopen((F),"r"))
  6536. #define  CLEANUP_IF_FILE_EXISTS(P) (void)fclose(P)
  6537. #else
  6538. #define  WRITE_FILEMODE     "w,recfm=v,reclen=255,blksize=6233"
  6539. #define  APPEND_FILEMODE    "a,recfm=v,reclen=255,blksize=6233"
  6540. #define  FTPTEMP_FILEMODE   "w,recfm=v,reclen=23444,blksize=23448"
  6541. #define  FTPBIN_FILEMODE   "wb,recfm=v,reclen=23444,blksize=23448"
  6542. #define  SYSOUT_FILEMODE    "w,recfm=v,reclen=133,print=yes"
  6543. #define  FILEMODE             "recfm=v,reclen=255,blksize=6233"
  6544. #define  FILEMODE_A           "recfm=v,reclen=133,print=yes"
  6545. #define  FILEMODE_T           "recfm=v,reclen=512,blksize=23440"
  6546. #define  FILEMODE_BM          "recfm=fb,reclen=4096,blksize=8192"
  6547. #define  OPEN_TEXT_FILE_FOR_WRITE(F)  afopen((F),"w","seq",FILEMODE)
  6548. #define  OPEN_TEXT_FILE_FOR_APPEND(F) afopen((F),"a","seq",FILEMODE)
  6549. #define  OPEN_SYSOUT_FILE(F)          afopen((F),"w","seq",FILEMODE_A)
  6550. #define  OPEN_FTP_TEMP_FILE(F)        afopen((F),"w","seq",FILEMODE_T)
  6551. #define  OPEN_FTP_BINARY_FILE(F)      afopen((F),"wb","seq",FILEMODE_T)
  6552. #define  OPEN_BOOKMANAGER_BINARY_FILE(F) \
  6553.                                       afopen((F),"wb","seq",FILEMODE_BM)
  6554. #define  OPEN_TEXT_FILE_FOR_WRITE_OR_APPEND(F,B)  \
  6555.          afopen((F),(B)?"a":"w","seq",FILEMODE)
  6556. #define  OPEN_OUTPUT_FILE_FOR_WRITE_OR_APPEND(F,B)  \
  6557.          afopen((F),(B)?"a":"w","seq",FILEMODE)
  6558. #define  TEST_IF_FILE_EXISTS(F,P)  (access((F),0) == 0)
  6559. #define  CLEANUP_IF_FILE_EXISTS(P) /* */
  6560. #endif
  6561.  
  6562. #define uppercase_in_place(C) {char *__cp;\
  6563.                      for(__cp=C;*__cp;__cp++) *__cp = toupper(*__cp);}
  6564.  
  6565. #define lowercase_in_place(C) {char *__cp;\
  6566.                      for(__cp=C;*__cp;__cp++) *__cp = tolower(*__cp);}
  6567.  
  6568. #define strip_trailing_in_place(C) {char *__cp;\
  6569.                      for(__cp=strchr((C),'\0');\
  6570.                          __cp>C && isspace(*(__cp-1)); __cp--);\
  6571.                      *__cp='\0';}
  6572.  
  6573. #define strip_trailing_junk_in_place(C) {char *__cp;\
  6574.                      for(__cp=strchr((C),'\0');\
  6575.                          __cp>C && !isgraph(*(__cp-1)); __cp--);\
  6576.                      *__cp='\0';}
  6577.  
  6578. #define copy_uppercase(A,B) {char *__cA,*__cB;\
  6579.                      for (__cA=A,__cB=B; *__cB;__cA++,__cB++)\
  6580.                          *__cA = toupper(*__cB);\
  6581.                      *__cA='\0';}
  6582.  
  6583. #define copy_lowercase(A,B) {char *__cA,*__cB;\
  6584.                      for (__cA=A,__cB=B; *__cB;__cA++,__cB++)\
  6585.                          *__cA = tolower(*__cB);\
  6586.                      *__cA='\0';}
  6587.  
  6588. #define copy_uppercase(A,B) {char *__cA,*__cB;\
  6589.                      for (__cA=A,__cB=B; *__cB;__cA++,__cB++)\
  6590.                          *__cA = toupper(*__cB);\
  6591.                      *__cA='\0';}
  6592.  
  6593. #define copy_uppercase_and_strip_trailing(A,B,C) {char *__cA,*__cB;\
  6594.                      for (__cA=A,__cB=B; *__cB;__cA++,__cB++)\
  6595.                          *__cA = toupper(*__cB);\
  6596.                      for (; __cA>A && isspace(*(__cA-1)); __cA--);\
  6597.                      *__cA='\0';C=__cA;}
  6598.  
  6599. #define copy_lowercase_and_strip_trailing(A,B,C) {char *__cA,*__cB;\
  6600.                      for (__cA=A,__cB=B; *__cB;__cA++,__cB++)\
  6601.                          *__cA = tolower(*__cB);\
  6602.                      for (; __cA>A && isspace(*(__cA-1)); __cA--);\
  6603.                      *__cA='\0';C=__cA;}
  6604.  
  6605. #define skip_leading_space(C)     (C) + strspn((C)," ")
  6606. #define skip_whitespace(C)        (C) + strspn((C)," \t")
  6607. #define skip_ISPF_whitespace(C)   (C) + strspn((C)," ,\t")
  6608. #define find_whitespace(A,B)      if (!(A=strpbrk((B)," \t")))\
  6609.                                      A = strchr((B),'\0');
  6610. #define find_ISPF_whitespace(A,B) if (!(A=strpbrk((B)," ,\t")))\
  6611.                                      A = strchr((B),'\0');
  6612.  
  6613. #define SPRINTF_IP_ADDRESS(A,B)  sprintf((A),"%d.%d.%d.%d",\
  6614.                                    (*(((unsigned char *)(&(B)))+0)),\
  6615.                                    (*(((unsigned char *)(&(B)))+1)),\
  6616.                                    (*(((unsigned char *)(&(B)))+2)),\
  6617.                                    (*(((unsigned char *)(&(B)))+3)))
  6618.  
  6619. /****** Data and structure definitions. ******************************/
  6620.  
  6621. enum accreq         {ACCESS_LOAD, ACCESS_CHECK, ACCESS_FREE};
  6622. enum dstype         {PDS, SEQ, UNK, JES};
  6623. enum extreq         {EXTRACT_IT, PRINT_IT, BOOKMARK_IT, BOOKMANAGE_IT};
  6624. enum gohow          {AS_NORMAL, AS_FILE, AS_NOTHING};
  6625. enum iomode         {NOCR, CRLF, RBIN};
  6626. enum gostat         {STATUS_OK, STATUS_EOF, STATUS_ERROR};
  6627. enum option         {OPTION_ALL, OPTION_VIEW, OPTION_OTHER};
  6628. enum ostype         {DEFAULT_OS, VM_OS};
  6629. enum scroll         {NO_SCROLL, UP, DOWN, LEFT, RIGHT, LOCATE};
  6630. enum tmpfun         {TEMP_CREATE, TEMP_CLOSE, TEMP_REMOVE};
  6631. enum retval         {
  6632.                      SERVER_READ_OK,
  6633.                      SERVER_READ_ERROR,
  6634.                      SERVER_BUFFER_ERROR,
  6635.                      SERVER_NO_MORE,
  6636.                      SERVER_READ_NOTHING
  6637.                     };
  6638.  
  6639. typedef unsigned int        IPADDRESS;
  6640. typedef int                 SOCKETNO;
  6641. typedef char                GOPHERTYPE;
  6642. typedef struct _textunit    TEXTUNIT;
  6643. typedef struct textline     TEXTLINE;
  6644. typedef struct texthdr      TEXTHDR;
  6645. typedef struct accessvector ACCESSVECTOR;
  6646. typedef struct connection   CONNECTION;
  6647. typedef struct extraction   EXTRACTION;
  6648. typedef struct gopherinfo   GOPHERINFO;
  6649. typedef struct gopherplus   GOPHERPLUS;
  6650. typedef struct ggcb         GGCB;
  6651. typedef struct recvstruct   RECV;
  6652. typedef struct menuitem     MENUITEM;
  6653. typedef struct sysout       SYSOUT;
  6654. typedef struct tempfile     TEMPFILE;
  6655. typedef enum   accreq       ACCREQ;
  6656. typedef enum   dstype       DSTYPE;
  6657. typedef enum   extreq       EXTREQ;
  6658. typedef enum   gohow        GOHOW;
  6659. typedef enum   gostat       GOSTAT;
  6660. typedef enum   iomode       IOMODE;
  6661. typedef enum   option       OPTION;
  6662. typedef enum   ostype       OSTYPE;
  6663. typedef enum   retval       RETVAL;
  6664. typedef enum   scroll       SCROLL;
  6665. typedef enum   tmpfun       TMPFUN;
  6666.  
  6667. #ifndef ACCESSRULE
  6668. #define ACCESSRULE  void
  6669. #endif
  6670.  
  6671. struct textline  {
  6672.                   struct textline    *next;
  6673.                   short               text_length;
  6674.                   short               tab_expanded_text_length;
  6675.                   char               *tab_expanded_text;
  6676.                   char                text[1];  /* dummy */
  6677.                  };
  6678.  
  6679. struct texthdr   {
  6680.                   int                 text_line_count;
  6681.                   TEXTLINE           *text_body_line;
  6682.                   short               text_max_length;
  6683.                   short               text_max_tab_expanded_length;
  6684.                   TEXTLINE           *first_text_line;
  6685.                   TEXTLINE           *current_text_line;
  6686.                   TEXTLINE           *last_text_line;
  6687.                  };
  6688.  
  6689. struct _textunit {
  6690.                   unsigned short         key;
  6691.                   unsigned short         num;
  6692.                   struct {
  6693.                           unsigned short len;
  6694.                           char           prm[80];
  6695.                          }               ent;
  6696.                  };
  6697.  
  6698. struct sysout    {
  6699.                   int        copies;
  6700.                   char       class  [2];
  6701.                   char       dest   [9];
  6702.                   char       userid [9];
  6703.                   char       forms  [5];
  6704.                   char       ucs    [5];
  6705.                  };
  6706.  
  6707. struct accessvector {
  6708.                      int          rulecount;
  6709.                      int          nextrule;
  6710.                      ACCESSRULE  *accessrule[1];
  6711.                     };
  6712.  
  6713. struct tempfile {
  6714.                  FILE        *fp;
  6715.                  char         ddname[12];
  6716.                  char         dsname[L_tmpnam];
  6717.                  IOMODE       crmode;
  6718.                 };
  6719.  
  6720. struct extraction {
  6721.                    int                   from_number;
  6722.                    int                   to_number;
  6723.                    int                   count;
  6724.                    DSTYPE                mode;
  6725.                    void                (*closer)();
  6726.                    Bool                  appending;
  6727.                    Bool                  blanking;
  6728.                    Bool                  tab_expanding;
  6729.                    EXTREQ                ex;
  6730.                    char                  panelname     [9];
  6731.                    char                  dsname       [65];
  6732.                    char                  separator    [81];
  6733.                    char                  member_prefix [9];
  6734.                    char                  ddname        [9];
  6735.                    char                  member        [9];
  6736.                   };
  6737.  
  6738. struct gopherinfo {
  6739.                    GOPHERTYPE            type;
  6740.                    int                   port;
  6741.                    TEXTHDR               thdr;
  6742.                    char                  path [GOPHER_PATH_LENGTH+1];
  6743.                    char                  host [GOPHER_HOST_LENGTH+1];
  6744.                    char                  desc [GOPHER_DESC_LENGTH+1];
  6745.                    char                  plus;
  6746.                    char                  bmds [65]; /* bookmark file */
  6747.                   };
  6748.  
  6749. struct menuitem {
  6750.     char          type;                  /* type of record to send   */
  6751.     char          desc     [GOPHER_DESC_LENGTH+1];
  6752.     char          select   [GOPHER_PATH_LENGTH+1];
  6753.     char          hostname [GOPHER_HOST_LENGTH+1];
  6754.     int           port;                  /* host port to connect to  */
  6755.     char          gopherplus;            /* null, '+' or '?' for ASK */
  6756.    };
  6757.  
  6758. struct connection  {
  6759.              char   *server_buf;
  6760.              char   *client_buf;
  6761.               int    mybufl;
  6762.               int    nbytes;
  6763.               int    ibuflen;
  6764.               int    bytes_returned;
  6765.               int    buf_index;
  6766.          SOCKETNO    ns;
  6767.              Bool    time_to_go_home;
  6768.              Bool    server_has_nothing;
  6769.              Bool    server_finished_replying;
  6770.              Bool    sending_text;
  6771.              Bool    receiving_text;
  6772.              Bool    dont_read;
  6773.              Bool    connected_to_server;
  6774.              Bool    connection_broken;
  6775.              Bool    closing_connection;
  6776.              Bool    is_ftp;
  6777.              char    server_hostname [MAXHOSTNAMELEN+1];
  6778.              char    buf [READ_BYTES];
  6779.                    };
  6780.  
  6781. struct Ftp {
  6782.             FILE                 *outfp;
  6783.             FILE                 *errfp;
  6784.             char                 *myname;
  6785.             struct hostent       *server_hostent;
  6786.             struct hostent       *client_hostent;
  6787.             int                   backlog;
  6788.             int                   myport;
  6789.             SOCKETNO              listensocket;
  6790.             Bool                  verboseflag;
  6791.             Bool                  replaceflag;
  6792.             Bool                  listflag;
  6793.             Bool                  nlstflag;
  6794.             Bool                  binary;
  6795.             Bool                  control_socket_opened;
  6796.             Bool                  listen_socket_opened;
  6797.             Bool                  accept_socket_opened;
  6798.             GOPHERTYPE            type;
  6799.             OSTYPE                os;
  6800.             IPADDRESS             hostaddress;
  6801.             CONNECTION            control_connection;
  6802.             CONNECTION            data_connection;
  6803.             struct sockaddr_in    bindsock;
  6804.             struct sockaddr_in    consock;
  6805.             char                  ftphack [16];
  6806.             char                  host [257];
  6807.             char                  user [257];
  6808.             char                  pass [257];
  6809.             char                  path [257];
  6810.             char                  client_hostname [257];
  6811.             char                  server_hostname [257];
  6812.            };
  6813.  
  6814. struct gopherplus {
  6815.                    int            dummy;   /* nothing yet */
  6816.                   };
  6817.  
  6818. struct recvstruct {
  6819.     int             sockfd;   /* socket descriptor for socket call */
  6820.     int             outlen;
  6821.     int             myport;
  6822.     int             bytes_read;
  6823.     Bool            binary;
  6824.     GOSTAT          readstatus;
  6825.     FILE           *outfp;    /* used by local (non-socket) interface*/
  6826.     FILE           *readfile;                 /* declare the file... */
  6827.     char           *fileptr;
  6828.     char           *wargptr;
  6829.     char           *mytelnet;
  6830.     char           *mybkmgr;
  6831.     char           *mydomain;
  6832.     ACCESSVECTOR   *accvector;
  6833.     GOPHERPLUS     *gopherplus;
  6834.     TEMPFILE       *temp;
  6835.     Bool          (*openfun)();
  6836.     Bool          (*readfun)();
  6837.     Bool          (*closefun)();
  6838.     struct hostent  clienthostent;
  6839.     char            pathtype;
  6840.     char            myname  [MAXHOSTNAMELEN+1];
  6841.     char            hostname[MAXHOSTNAMELEN+1];  /* client host name */
  6842.     char            hosttest[MAXHOSTNAMELEN+1];  /* client host name */
  6843.     char            buffer  [RBUFSIZE]; /* client's character string */
  6844.     char            dsname  [RBUFSIZE];
  6845.     char            sockbuf [OUTBUFSIZE];    /* socket output buffer */
  6846.    };
  6847.  
  6848. struct ggcb {
  6849.              char    *gopher_command;
  6850.              char    *extract_separator_line;
  6851.              char    *mytelnet;
  6852.              char    *mybkmgr;
  6853.              char    *mydomain;
  6854.              FILE    *debug_file;
  6855.              FILE    *extract_file;
  6856.              RECV    *recvp;
  6857.        EXTRACTION    *extractionp;
  6858.        GOPHERINFO    *ginfo;
  6859. #ifdef FETCH
  6860.               int   (*isplink_pointer)();
  6861.               int   (*ispexec_pointer)();
  6862. #endif
  6863.               int     ispfrc;
  6864.               int     text_find_left_bound;
  6865.               int     text_find_right_bound;
  6866.               int     myport;
  6867.              Bool     test_mode;
  6868.              Bool     debug_mode;
  6869.              Bool     quit;
  6870.              Bool     local_mode;
  6871.              Bool     extract_tab_expanding;
  6872.              Bool     extract_appending;
  6873.              Bool     extract_blank_before_separator;
  6874.              Bool     extract_write_error;
  6875.              Bool     extract_close_error;
  6876.              Bool     warn_overwrite;
  6877.              Bool     warn_append;
  6878.              Bool     setmsg;
  6879.              Bool     autoscroll;
  6880.              Bool     autocursor;
  6881.              Bool     setcursor;
  6882.              Bool     printing;
  6883.         IPADDRESS     client_ip_address;
  6884.         IPADDRESS     server_ip_address;
  6885.           TEXTHDR     thdr;
  6886.        CONNECTION     gopher_connection;
  6887.              char     client_ip_addrstr   [16];
  6888.              char     server_ip_addrstr   [16];
  6889.              char     ggserver            [MAXHOSTNAMELEN+1];
  6890.              char     ggclient            [MAXHOSTNAMELEN+1];
  6891.              char     client_hostname     [MAXHOSTNAMELEN+1];
  6892.              char     server_hostname     [MAXHOSTNAMELEN+1];
  6893.              char     text_find_string    [81];
  6894.              char     text_dispchar;
  6895.              char     text_find_what;
  6896.              char     text_find_type;
  6897.              char     text_find_trans;
  6898.              char     current_bookmark_ds [65];
  6899.             };
  6900.  
  6901. #ifndef I370
  6902. extern  char          ebcdictoascii[];
  6903. extern  char          asciitoebcdic[];
  6904. #endif
  6905.  
  6906. #ifndef FETCH
  6907. extern  int           isplink();
  6908. extern  int           ispexec();
  6909. #endif
  6910.  
  6911. /****** Procedure and function declarations. *************************/
  6912.  
  6913. extern Bool         GGacces (RECV *, ACCREQ);
  6914. extern DSTYPE       GGalloc (char *, char *, DSTYPE, int);
  6915. extern void         GGbarf  (RECV *, char *);
  6916. extern Bool         GGbin   (GGCB *, GOPHERINFO *, GOHOW);
  6917. extern Bool         GGbkmgr (GGCB *, GOPHERINFO *, GOHOW);
  6918. extern void         GGclrtx (GGCB *, GOPHERINFO *);
  6919. extern Bool         GGconn  (GGCB *, CONNECTION *);
  6920. extern Bool         GGcso   (GGCB *, GOPHERINFO *, GOHOW);
  6921. extern Bool         GGdbm   (GGCB *, GOPHERINFO *);
  6922. extern void         GGdfail (int,    __S99parms *);
  6923. extern Bool         GGdir   (GGCB *, GOPHERINFO *, GOHOW);
  6924. extern void         GGdisc  (GGCB *, CONNECTION *);
  6925. extern int          GGdispl (GGCB *, char *);
  6926. extern void         GGdsopt (GGCB *, char *);
  6927. extern void         GGdump  (GGCB *, char *, char *, int);
  6928. extern void         GGesrvr (GGCB *, CONNECTION *);
  6929. extern void         GGfreem (GGCB *, char *,char *);
  6930. extern Bool         GGftp   (RECV *, struct Ftp *);
  6931. extern FILE        *GGgetds (GGCB *, EXTRACTION *);
  6932. extern void         GGgetm  (GGCB *, char **,int,char *);
  6933. extern Bool         GGgofor (GGCB *, GOPHERINFO *, GOHOW);
  6934. extern Bool         GGgsrvl (GGCB *, CONNECTION *, char **, IOMODE);
  6935. extern void         GGierr  (GGCB *);
  6936. extern int          GGiget  (GGCB *, char *);
  6937. extern Bool         GGinfo  (GGCB *, GOPHERINFO *);
  6938. extern Bool         GGispf  (GGCB *, char *);
  6939. extern Bool         GGivget (GGCB *, char *, char *,int);
  6940. extern Bool         GGivput (GGCB *, char *, char *,int);
  6941. extern Bool         GGmenu  (GGCB *, char *);
  6942. extern void         GGmtfer (int,    char*);
  6943. extern Bool         GGouts  (RECV *, char *, int);
  6944. extern TEXTLINE    *GGouttx (GGCB *, char *, GOPHERINFO *, int);
  6945. extern Bool         GGproc  (RECV *, int);
  6946. extern int          GGrexx  (RECV *, char *, char *);
  6947. extern int          GGsleep (int);
  6948. extern Bool         GGsockt (GGCB *, CONNECTION *);
  6949. extern void         GGsopt  (GGCB *, OPTION);
  6950. extern FILE        *GGtemp  (RECV *, TEMPFILE *, TMPFUN);
  6951. extern Bool         GGtnet  (GGCB *, GOPHERINFO *, GOHOW);
  6952. extern int          GGtso   (char *);
  6953. extern char        *GGtype  (GOPHERTYPE);
  6954. extern Bool         GGunalc (char *);
  6955. extern void         GGview  (GGCB *, GOPHERINFO *, TEXTHDR *, char *);
  6956. extern Bool         GGvtx   (GGCB *, GOPHERINFO *, GOHOW);
  6957. extern Bool         GGwais  (GGCB *, GOPHERINFO *, GOHOW);
  6958. extern Bool         GGwhois (GGCB *, GOPHERINFO *, GOHOW);
  6959. extern int          GGwto   (char *);
  6960. extern Bool         GGxlist (GGCB *, char *);
  6961. extern Bool         GGxtx   (GGCB *, GOPHERINFO *, EXTREQ);
  6962.  
  6963. #ifndef SUPPRESS_V_DECLARATION
  6964. extern void         GGpmsg  (GGCB *, int, char *, char *, ...);
  6965. #endif
  6966.  
  6967. /*********************************************************************/
  6968.  
  6969. static char copyright_notice[] =
  6970.    "Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993   \n\
  6971.     GOPHER server due to Shawn Hart at the University of Delaware.  \n\
  6972.     GOPHER client due to Steve Bacher at Draper Laboratory.         \n\
  6973.     SAS modifications due to Dale Ingold at SAS Institute, Inc.     \n\
  6974.                                                                     \n\
  6975.     GOPHER server due to Shawn Hart at the University of Delaware.  \n\
  6976.                                                                     \n\
  6977.     This software is provided on an 'AS IS' basis.  All warranties, \n\
  6978.     including the implied warranties of merchantability and fitness,\n\
  6979.     are expressly denied.                                           \n\
  6980.                                                                     \n\
  6981.     Provided this copyright notice is included, this software may   \n\
  6982.     be freely distributed and not offered for sale.                 \n\
  6983.                                                                     \n\
  6984.     Changes or modifications may be made and used only by the maker \n\
  6985.     of same, and not further distributed.  Such modifications should\n\
  6986.     be mailed to the author for consideration for addition to the   \n\
  6987.     software and incorporation in subsequent releases.";
  6988.  
  6989. /*********************************************************************/
  6990.  
  6991. ./ ADD NAME=GGRX
  6992.  
  6993.  /********************************************************************/
  6994.  /*                                                                  */
  6995.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  6996.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  6997.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  6998.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  6999.  /*                                                                  */
  7000.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  7001.  /* including the implied warranties of merchantability and fitness, */
  7002.  /* are expressly denied.                                            */
  7003.  /*                                                                  */
  7004.  /* Provided this copyright notice is included, this software may    */
  7005.  /* be freely distributed and not offered for sale.                  */
  7006.  /*                                                                  */
  7007.  /* Changes or modifications may be made and used only by the maker  */
  7008.  /* of same, and not further distributed.  Such modifications should */
  7009.  /* be mailed to the author for consideration for addition to the    */
  7010.  /* software and incorporation in subsequent releases.               */
  7011.  /*                                                                  */
  7012.  /********************************************************************/
  7013.  
  7014. /* -------------------- "ggrx.h" include member -------------------- */
  7015.  
  7016. #define PARAMETER   unsigned int
  7017. #define LASTPARM(X) ((unsigned int)(X) | 0x80000000)
  7018.  
  7019. #define INVOKE_EXEC_AS_COMMAND            (unsigned int)0x80000000
  7020. #define INVOKE_EXEC_AS_EXTERNAL_FUNCTION  (unsigned int)0x40000000
  7021. #define INVOKE_EXEC_AS_SUBROUTINE         (unsigned int)0x20000000
  7022. #define RETURN_EXTENDED_RETURN_CODES      (unsigned int)0x10000000
  7023.  
  7024. /* the following take W as a work block extension address. */
  7025.  
  7026. #define EXEC_INVOKED_AS_COMMAND(W)            ((W)->flags && 0x7fffffff)
  7027. #define EXEC_INVOKED_AS_EXTERNAL_FUNCTION(W)  ((W)->flags && 0xbfffffff)
  7028. #define EXEC_INVOKED_AS_SUBROUTINE(W)         ((W)->flags && 0xdfffffff)
  7029. #define EXEC_RETURNS_EXTENDED_RETURN_CODES(W) ((W)->flags && 0xefffffff)
  7030.  
  7031. typedef int (*Rexxfun)();
  7032.  
  7033. struct envblock {
  7034.                  char                 id      [8];   /* "ENVBLOCK" */
  7035.                  char                 version [4];   /* "0200"     */
  7036.                  int                  length;        /* 320        */
  7037.                  struct parmblock    *parmblock;
  7038.                  void                *userfield;
  7039.                  struct workblockext *workblok_ext;
  7040.                  void                *irxexte;
  7041.                  void                *error_call_addr;
  7042.                  void                *reserved;
  7043.                  char                 error_msgid [8];
  7044.                  char                 primary_error_message    [80];
  7045.                  char                 alternate_error_message [160];
  7046.  /* The following fields are valid in TSO/E 2.3.1 (?) and higher. */
  7047.                  void                *compgmtb;
  7048.                  void                *attnrout_parmptr;
  7049.                 };
  7050.  
  7051. struct parmblock {
  7052.                   char                id       [8];  /* "IRXPARMS" */
  7053.                   char                version  [4];  /* "0200"     */
  7054.                   char                language [3];
  7055.                   char                reserved [1];
  7056.                   void               *modnamet;
  7057.                   void               *subcomtb;
  7058.                   void               *packtb;
  7059.                   char                parsetok [8];
  7060.                   unsigned int        flags;
  7061.                   unsigned int        masks;
  7062.                   int                 subpool;
  7063.                   char               *addrspn [8];
  7064.                   char                END [8];       /* 8X'FF'     */
  7065.                  };
  7066.  
  7067. struct workblockext {
  7068.                      struct execblock    *execblk;
  7069.                      void                *argtable;
  7070.                      unsigned int         flags;
  7071.                      struct instblock    *instblk;
  7072.                      struct cppl         *cppl;
  7073.                      struct evalblock    *evalblock;
  7074.                      char                *workarea;
  7075.                      void                *userfield;
  7076.  /* The following fields are valid in TSO/E 2.3.1 (?) and higher. */
  7077.                      void                *rtproc;
  7078.                      char                *source_address;
  7079.                      char                *source_length;
  7080.                     };
  7081.  
  7082. struct instblock {
  7083.                   int dummy;
  7084.                  };
  7085.  
  7086. struct evalblock {
  7087.                   int dummy;
  7088.                  };
  7089.  
  7090. struct execblock {
  7091.                   char       acryn  [8];       /* "IRXEXECB" */
  7092.                   int        length;
  7093.                   int        reserved1;
  7094.                   char       member [8];
  7095.                   char       ddname [8];
  7096.                   char       subcom [8];
  7097.                   char      *dsnptr;
  7098.                   int        dsnlen;
  7099.                  };
  7100.  
  7101. struct shvblock {
  7102.                  struct shvblock    *shvnext;
  7103.                  int                 shvuser;
  7104.                  char                shvcode;
  7105.                  char                shvret;
  7106.                  short               reserved;
  7107.                  int                 shvbufl;
  7108.                  char               *shvnama;
  7109.                  int                 shvnaml;
  7110.                  char               *shvvala;
  7111.                  int                 shvvall;
  7112.                 };
  7113.  
  7114. struct cppl {
  7115.              void    *cpplcbuf;
  7116.              void    *cpplupt;
  7117.              void    *cpplpscb;
  7118.              void    *cpplect;
  7119.             };
  7120.  
  7121.  
  7122. /* --------------------- end of "ggrx.h" include ------------------- */
  7123.  
  7124. ./ ADD NAME=GGSASC
  7125.  
  7126.  /********************************************************************/
  7127.  /*                                                                  */
  7128.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  7129.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  7130.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  7131.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  7132.  /*                                                                  */
  7133.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  7134.  /* including the implied warranties of merchantability and fitness, */
  7135.  /* are expressly denied.                                            */
  7136.  /*                                                                  */
  7137.  /* Provided this copyright notice is included, this software may    */
  7138.  /* be freely distributed and not offered for sale.                  */
  7139.  /*                                                                  */
  7140.  /* Changes or modifications may be made and used only by the maker  */
  7141.  /* of same, and not further distributed.  Such modifications should */
  7142.  /* be mailed to the author for consideration for addition to the    */
  7143.  /* software and incorporation in subsequent releases.               */
  7144.  /*                                                                  */
  7145.  /********************************************************************/
  7146.  
  7147. /* ------------------- "ggsasc.h" include member ------------------- */
  7148.  
  7149. #ifdef SASC
  7150.  
  7151. #define I370
  7152.  
  7153. #include <dynam.h>
  7154.  
  7155. #define FETCH
  7156.  
  7157. /*
  7158.  * DEBUG is an automatic preprocessor symbol set by SAS/C if the DEBUG
  7159.  * option is specified.
  7160.  */
  7161.  
  7162. #ifdef DEBUG
  7163. #define ACTUAL_OR_INLINE __actual
  7164. #else
  7165. #define ACTUAL_OR_INLINE __inline
  7166. #endif
  7167.  
  7168.  ACTUAL_OR_INLINE void (*fetch( const char *modname ))()
  7169.  {
  7170.    void (*fpp)();
  7171.  
  7172.    loadm( modname, &fpp );
  7173.    return( fpp );
  7174.  }
  7175.  
  7176.  ACTUAL_OR_INLINE int (*release( void (*fpp)() ))
  7177.  {
  7178.    unloadm( fpp );
  7179.    return( 0 );
  7180.  }
  7181.  
  7182.  
  7183. #ifndef __SVC99
  7184.  
  7185.   #define __SVC99  1
  7186.  
  7187.   #include <code.h>
  7188.  
  7189.   struct __S99struc
  7190.     {
  7191.       unsigned char   __S99RBLN;  /* length of request block..20      */
  7192.       unsigned char   __S99VERB;  /* verb code                        */
  7193.       unsigned short  __S99FLAG1; /* FLAGS1 field of SVC99 Req Block  */
  7194.       unsigned short  __S99ERROR; /* error code field                 */
  7195.       unsigned short  __S99INFO;  /* information reason code          */
  7196.       void           *__S99TXTPP; /* address of text unit pointer list*/
  7197.       int             __reserved; /* reserved..will always be 0       */
  7198.       unsigned int    __S99FLAG2; /* FLAGS2 field..can only be filled */
  7199.                                   /* in by APF authorized programs    */
  7200.     };
  7201.  
  7202.   typedef struct __S99struc __S99parms;
  7203.  
  7204.   ACTUAL_OR_INLINE int svc99(__S99parms* svc99parmlist)
  7205.     { return( (_ldregs(R1, &svc99parmlist),
  7206.                _code(0, 0x9680, 0x1000),
  7207.                _code(0, 0x0a63),
  7208.                _stregs(R15) ) );
  7209.     }
  7210.  
  7211. #endif
  7212.  
  7213. #define FALSE 0
  7214. #define TRUE  1
  7215.  
  7216. #include <lcio.h>
  7217.  
  7218. #define  MAXHOSTNAMELEN     64
  7219.  
  7220. #define  __ctest(X)  fprintf(stderr,\
  7221.                      "GGMVS: CTEST is not supported by this compiler.")
  7222.  
  7223. #endif
  7224.  
  7225. ./ ADD NAME=GGSVC
  7226.  
  7227.  /********************************************************************/
  7228.  /*                                                                  */
  7229.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  7230.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  7231.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  7232.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  7233.  /*                                                                  */
  7234.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  7235.  /* including the implied warranties of merchantability and fitness, */
  7236.  /* are expressly denied.                                            */
  7237.  /*                                                                  */
  7238.  /* Provided this copyright notice is included, this software may    */
  7239.  /* be freely distributed and not offered for sale.                  */
  7240.  /*                                                                  */
  7241.  /* Changes or modifications may be made and used only by the maker  */
  7242.  /* of same, and not further distributed.  Such modifications should */
  7243.  /* be mailed to the author for consideration for addition to the    */
  7244.  /* software and incorporation in subsequent releases.               */
  7245.  /*                                                                  */
  7246.  /********************************************************************/
  7247.  
  7248. /* ------------------- "ggsvc.h" include member -------------------- */
  7249.  
  7250. /*
  7251.  *  Usage:   SVC(SVC_NUMBER   svcnumber,
  7252.  *               SVC_REGISTER register15,
  7253.  *               SVC_REGISTER register0,
  7254.  *               SVC_REGISTER register1)
  7255.  *
  7256.  */
  7257.  
  7258. #define SVC_NUMBER             unsigned char
  7259. #define SVC_REGISTER           unsigned int
  7260.  
  7261. #define SVC(_num,_r15,_r00,_r01) GGasvc((SVC_NUMBER)     (_num),\
  7262.                                         (SVC_REGISTER *) (_r15),\
  7263.                                         (SVC_REGISTER *) (_r00),\
  7264.                                         (SVC_REGISTER *) (_r01))
  7265. extern void GGasvc (SVC_NUMBER,
  7266.                     SVC_REGISTER *,
  7267.                     SVC_REGISTER *,
  7268.                     SVC_REGISTER *);
  7269.  
  7270. /* -------------------- end of "ggsvc.h" include ------------------- */
  7271.  
  7272. ./ ADD NAME=GGSVC99
  7273.  
  7274.  /********************************************************************/
  7275.  /*                                                                  */
  7276.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  7277.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  7278.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  7279.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  7280.  /*                                                                  */
  7281.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  7282.  /* including the implied warranties of merchantability and fitness, */
  7283.  /* are expressly denied.                                            */
  7284.  /*                                                                  */
  7285.  /* Provided this copyright notice is included, this software may    */
  7286.  /* be freely distributed and not offered for sale.                  */
  7287.  /*                                                                  */
  7288.  /* Changes or modifications may be made and used only by the maker  */
  7289.  /* of same, and not further distributed.  Such modifications should */
  7290.  /* be mailed to the author for consideration for addition to the    */
  7291.  /* software and incorporation in subsequent releases.               */
  7292.  /*                                                                  */
  7293.  /********************************************************************/
  7294.  
  7295. /* ------------------ "ggsvc99.h" include member ------------------- */
  7296.  
  7297.  /********************************************************************/
  7298.  /*                                                                  */
  7299.  /* The contents of this header are taken from the IBM assembler     */
  7300.  /* macros IEFZB4D0 and IEFZB4D2, which are                          */
  7301.  /* (C) Copyright IBM Corp.  1981, 1990                              */
  7302.  /*                                                                  */
  7303.  /********************************************************************/
  7304.  
  7305. #define  S99VRBAL  0x01             /* ALLOCATION                    */
  7306. #define  S99VRBUN  0x02             /* UNALLOCATION                  */
  7307. #define  S99VRBCC  0x03             /* CONCATENATION                 */
  7308. #define  S99VRBDC  0x04             /* DECONCATENATION               */
  7309. #define  S99VRBRI  0x05             /* REMOVE IN-USE                 */
  7310. #define  S99VRBDN  0x06             /* DDNAME ALLOCATION             */
  7311. #define  S99VRBIN  0x07             /* INFORMATION RETRIEVAL         */
  7312. #define  S99NOCNV  0x40             /* ALLOC FUNCTION-DO NOT USE AN  */
  7313.                                     /* EXISTING ALLOCATION TO SATISFY*/
  7314.                                     /* THE REQUEST                   */
  7315. #define  DALDDNAM   0x0001          /* DDNAME                        */
  7316. #define  DALDSNAM   0x0002          /* DSNAME                        */
  7317. #define  DALMEMBR   0x0003          /* MEMBER NAME                   */
  7318. #define  DALSTATS   0x0004          /* DATA SET STATUS               */
  7319. #define  DALNDISP   0x0005          /* DATA SET DISPOSITION          */
  7320. #define  DALTRK     0x0007          /* TRACK SPACE TYPE              */
  7321. #define  DALBLKLN   0x0009          /* BLOCK LENGTH                  */
  7322. #define  DALPRIME   0x000a          /* PRIMARY SPACE ALLOCATION      */
  7323. #define  DALSECND   0x000b          /* SECONDARY SPACE ALLOCATION    */
  7324. #define  DALDIR     0x000c          /* DIRECTORY BLOCK ALLOCATION    */
  7325. #define  DALSYSOU   0x0018          /* SYSOUT                        */
  7326. #define  DALSFMNO   0x001a          /* SYSOUT FORMS NUMBER           */
  7327. #define  DALCOPYS   0x001d          /* SYSOUT COPIES                 */
  7328. #define  DALUCS     0x0029          /* UNIVERSAL CHARACTER SET       */
  7329. #define  DALBLKSZ   0x0030          /* DCB BLOCKSIZE                 */
  7330. #define  DALDSORG   0x003c          /* DATA SET ORGANIZATION         */
  7331. #define  DALLRECL   0x0042          /* DCB LOGICAL RECORD LENGTH     */
  7332. #define  DALRECFM   0x0049          /* DCB RECORD FORMAT             */
  7333. #define  DALPERMA   0x0052          /* PERMANENTLY ALLOCATED ATTRIB  */
  7334. #define  DALRTDDN   0x0055          /* RETURN DDNAME                 */
  7335. #define  DALRTDSN   0x0056          /* RETURN DSNAME                 */
  7336. #define  DALRTORG   0x0057          /* RETURN D.S. ORGANIZATION      */
  7337. #define  DALSUSER   0x0058          /* SYSOUT REMOTE WORKSTATION     */
  7338. #define  DALUSRID   0x0063          /* SYSOUT USER ID                */
  7339. #define  DUNDDNAM   0x0001          /* DDNAME                        */
  7340. #define  DUNDSNAM   0x0002          /* DSNAME                        */
  7341. #define  DUNUNALC   0x0007          /* UNALLOC OPTION                */
  7342. #define  SHR        0x08
  7343. #define  NEW        0x04
  7344. #define  MOD        0x02
  7345. #define  OLD        0x01
  7346. #define  KEEP       0x08
  7347. #define  DELETE     0x04
  7348. #define  CATLG      0x02
  7349. #define  UNCATLG    0x01
  7350. #define  RECFM_F    0x80
  7351. #define  RECFM_V    0x40
  7352. #define  RECFM_U    0xc0
  7353. #define  RECFM_D    0x20
  7354. #define  RECFM_T    0x20
  7355. #define  RECFM_B    0x10
  7356. #define  RECFM_S    0x08
  7357. #define  RECFM_A    0x04
  7358. #define  RECFM_M    0x02
  7359. #define  RECFM_FB   (RECFM_F | RECFM_B)
  7360. #define  RECFM_VB   (RECFM_V | RECFM_B)
  7361. #define  DSORG_PS   0x4000
  7362. #define  DSORG_PO   0x0200
  7363.  
  7364. /* ------------------- end of "ggsvc99.h" include ------------------ */
  7365.  
  7366. ./ ADD NAME=GGUSER
  7367.  
  7368.  /********************************************************************/
  7369.  /*                                                                  */
  7370.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  7371.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  7372.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  7373.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  7374.  /*                                                                  */
  7375.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  7376.  /* including the implied warranties of merchantability and fitness, */
  7377.  /* are expressly denied.                                            */
  7378.  /*                                                                  */
  7379.  /* Provided this copyright notice is included, this software may    */
  7380.  /* be freely distributed and not offered for sale.                  */
  7381.  /*                                                                  */
  7382.  /* Changes or modifications may be made and used only by the maker  */
  7383.  /* of same, and not further distributed.  Such modifications should */
  7384.  /* be mailed to the author for consideration for addition to the    */
  7385.  /* software and incorporation in subsequent releases.               */
  7386.  /*                                                                  */
  7387.  /********************************************************************/
  7388.  
  7389. /* ------------------- "gguser.h" include member ------------------- */
  7390.  
  7391. /* Include file for locally customized values. */
  7392.  
  7393. /* Define levels of C/370 and TCP/IP.  This controls support for
  7394.  * fetching of non-C load modules and socket error reporting.
  7395.  */
  7396.  
  7397. /* #define  C370V1    /* define this if C/370 Version 1 */
  7398.    #define  C370V2    /* define this if C/370 Version 2 or higher */
  7399. /* #define  SASC      /* define this if SAS/C compiler */
  7400.  
  7401. /* #define  TCPIPV1   /* define this if TCP/IP Version 1 */
  7402.    #define  TCPIPV2   /* define this if TCP/IP Version 2 or higher */
  7403. /* #define  SNSTCPIP  /* define this if SNS/TCPAccess    */
  7404.  
  7405. /* #define  ISPFV2    /* define this if ISPF Version 2 or earlier */
  7406.    #define  ISPFV3    /* define this if ISPF Version 3 or later   */
  7407.  
  7408. /*
  7409.  * If you know about the IBM TCP/IP "CMXLATE" function, and you want
  7410.  * to use it, set the define accordingly.
  7411.  * SNS/TCP users should NOT set this define.
  7412.  */
  7413.  
  7414.    #define USE_CMXLATE
  7415. /* #undef  USE_CMXLATE */
  7416.  
  7417. /*
  7418.  * Define this if you want DEST, FORMS and UCB for print requests.
  7419.  * Undefine it if you don't (you get just CLASS and COPIES).
  7420.  */
  7421.  
  7422.    #define FULLSYSOUT
  7423. /* #undef  FULLSYSOUT */
  7424.  
  7425. /* Define the following defaults for your installation. */
  7426. /* Use XTELNET if you like the CSOCK package from UCLA. */
  7427.  
  7428.    #define  TELNET_COMMAND_NAME     "TELNET"
  7429. /* #define  TELNET_COMMAND_NAME     "XTELNET" */
  7430.  
  7431.    #define  BOOKMGR_COMMAND_NAME    "BOOKMGR"
  7432.  
  7433. /* Define the following if you want to use the autologin */
  7434. /* feature of XTELNET (i.e. XTELNET -l userid(/password) */
  7435.  
  7436. /* #define  XTELNET_AUTOLOGIN */
  7437.    #undef   XTELNET_AUTOLOGIN
  7438.  
  7439. /* Define this if the server host name set by the "+" frob
  7440.  * should have the domain name appended.  Note that this will
  7441.  * affect how the hostname needs to be specified for a
  7442.  * Path=(pdsmember) specification - it must match the local host
  7443.  * the way it is generated here.  Of course, host=+ will do it anyway.
  7444.  */
  7445.  
  7446.    #define  APPEND_DOMAIN_NAME_TO_SELF
  7447. /* #undef   APPEND_DOMAIN_NAME_TO_SELF */
  7448.  
  7449. /* Define the following if you want logging messages */
  7450. /* sent as write-to-programmer messages to SYSLOG.   */
  7451.  
  7452.    #define  LOG_GOPHER_ACCESSES
  7453. /* #undef   LOG_GOPHER_ACCESSES */
  7454.  
  7455. /*
  7456.  * Turn on for TCP-level debugging output (you probably don't want to
  7457.  * unless your TCP/IP stuff is really broken and I can't help you).
  7458.  */
  7459.  
  7460. /* #define GOPHER_DEBUG       */
  7461.    #undef  GOPHER_DEBUG
  7462.  
  7463. /*
  7464.  * Turn on for MTF-level debugging output.
  7465.  */
  7466.  
  7467. /* #define DEBUGMTF    */
  7468.    #undef  DEBUGMTF
  7469.  
  7470. /*
  7471.  * Turn on to debug the access table matching rules.
  7472.  */
  7473.  
  7474. /* #define ACCESS_DEBUG */
  7475.    #undef  ACCESS_DEBUG
  7476.  
  7477. /* Server and MTF stuff. */
  7478.  
  7479. /* #define  MTF_TASKS           8 */
  7480. #define  MTF_TASKS           1  /* lest REXX multitasking lossage */
  7481. #define  TCP_QUEUE_LENGTH   20
  7482. #define  SERV_TCP_PORT      70
  7483. #define  CONNECT_TIME_OUT   60
  7484. #define  DEFAULT_DIRECTORY  "DD:GGGOPHER"
  7485. #define  ACCESS_TABLE       "DD:GGACCESS"
  7486. #define  DEBUG_FILE         "DD:GGDEBUG"
  7487. #define  PARAMETER_FILE     "DD:GGPARMS"
  7488. #define  MY_DOMAIN_SUFFIX   ".DRAPER.COM"
  7489. #define  GOPHER_ADMIN       "batchman@draper.com"
  7490.  
  7491. /* note: could get MY_DOMAIN_SUFFIX from TCPIP startup - what call? */
  7492.  
  7493. /* Client stuff. */
  7494.  
  7495. #define  INITIAL_TYPE   GOPHER_DIRECTORY
  7496. #define  INITIAL_PORT   GOPHER_PORT_NUMBER
  7497. #define  INITIAL_PATH   ""
  7498. #define  INITIAL_HOST   "MVS.DRAPER.COM"
  7499. #define  INITIAL_DESC   "Root"
  7500.  
  7501. /********************************************************************/
  7502. /**** You probably should not modify anything below this point.  ****/
  7503. /********************************************************************/
  7504.  
  7505. /* Server and client stuff. */
  7506.  
  7507. #define  IDENT_HOST_FROB    "+"
  7508. #define  LOCAL_HOST_FROB    "-"
  7509.  
  7510. /********************************************************************/
  7511. /* following are MVS file type identifiers.  They must appear at the
  7512.    beginning of the file they're identifying.                        */
  7513. /********************************************************************/
  7514.  
  7515. #define  MENUIDENT    "GOPHER_MENU"
  7516. #define  INDEXIDENT   "GOPHER_INDEX"
  7517.  
  7518. /********************************************************************/
  7519. /*  following are tokens for menu GOPHER identifiers.    */
  7520. /********************************************************************/
  7521.  
  7522. #define  TOKTYPE      "TYPE"
  7523. #define  TYPETOK      0
  7524. #define  TOKNAME      "NAME"
  7525. #define  NAMETOK      1
  7526. #define  TOKPATH      "PATH"
  7527. #define  PATHTOK      2
  7528. #define  TOKHOST      "HOST"
  7529. #define  HOSTTOK      3
  7530. #define  TOKPORT      "PORT"
  7531. #define  PORTTOK      4
  7532. #define  TOKEND       "END"
  7533. #define  ENDTOK       5
  7534. #define  TOKCOMMENT1  '*'
  7535. #define  TOKCOMMENT2  '#'
  7536. #define  TOKCOMMENT3  '!'
  7537. #define  COMMENTTOK   6
  7538. #define  TOKDISPLAY   "DISPLAY"
  7539. #define  DISPLAYTOK   7
  7540. #define  TOKSELECT    "SELECTOR"
  7541. #define  SELECTTOK    8
  7542. #define  NULLTOK      9
  7543.  
  7544. /********************************************************************/
  7545. /*  types of   "types" - operands of the TYPE keyword in directories.*/
  7546. /********************************************************************/
  7547.  
  7548. #define  TYPEFILE        "FILE"
  7549. #define  TYPEMENU        "DIRECTORY"
  7550. #define  TYPECSO         "CSO"
  7551. #define  TYPEINDEX       "INDEX"
  7552. #define  TYPETELNET      "TELNET"
  7553. #define  TYPETN3270      "TN3270"
  7554. #define  TYPEBINARY      "BINARY"
  7555. #define  TYPEWHOIS       "WHOIS"
  7556. #define  TYPEBOOKMANAGER "BOOKMANAGER"
  7557.  
  7558. /********************************************************************/
  7559. /*  used by the REXX Interface                                      */
  7560. /********************************************************************/
  7561.  
  7562.   /* Be sure to include all 8 bytes, including blanks, in below */
  7563.  
  7564. #define  REXX_EXEC_LIBRARY_DDNAME   "GGEXEC  "
  7565. #define  REXX_EXEC_SUBCOM           "        "
  7566.  
  7567. ./ ENDUP
  7568. ?!
  7569. //C        EXEC MDLOAD,BS='6160',TRK1='25',TRK2='1',TO='C'
  7570. //SYSIN    DD   DATA,DLM='?!'
  7571. ./ ADD NAME=GGACCES
  7572.  
  7573.  /********************************************************************/
  7574.  /*                                                                  */
  7575.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  7576.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  7577.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  7578.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  7579.  /*                                                                  */
  7580.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  7581.  /* including the implied warranties of merchantability and fitness, */
  7582.  /* are expressly denied.                                            */
  7583.  /*                                                                  */
  7584.  /* Provided this copyright notice is included, this software may    */
  7585.  /* be freely distributed and not offered for sale.                  */
  7586.  /*                                                                  */
  7587.  /* Changes or modifications may be made and used only by the maker  */
  7588.  /* of same, and not further distributed.  Such modifications should */
  7589.  /* be mailed to the author for consideration for addition to the    */
  7590.  /* software and incorporation in subsequent releases.               */
  7591.  /*                                                                  */
  7592.  /********************************************************************/
  7593.  
  7594. #pragma  csect(code,  "GG@ACCES")
  7595. #pragma  csect(static,"GG$ACCES")
  7596.  
  7597. #define ACCESSRULE        struct accessrule
  7598.  
  7599. #include "gg.h"
  7600.  
  7601. #define RULEPTRSIZE       sizeof(ACCESSRULE *)
  7602. #define ACCFILESIZE       63
  7603.  
  7604. /*===================================================================*/
  7605.  
  7606. struct accessrule {
  7607.                    int       number;
  7608.                    int       hostcount;
  7609.                    int       hosttextlen;
  7610.                    int       major_weight;
  7611.                    int       minor_weight;
  7612.                    int       part1len;
  7613.                    int       part2len;
  7614.                    Bool      wildcard;
  7615.                    char      accfile   [ACCFILESIZE+1];
  7616.                    char      filepart1 [ACCFILESIZE+1];
  7617.                    char      filepart2 [ACCFILESIZE+1];
  7618.                    char      hosttext  [1];
  7619.                   };
  7620.  
  7621. /*
  7622.  * There are three logical entry points:
  7623.  *
  7624.  *  load_access_rules is called from the server main task.
  7625.  *  check_access_rules is called from the server subtask.
  7626.  *  free_access_rules is called from the server main task.
  7627.  *
  7628.  */
  7629.  
  7630. /*===================================================================*/
  7631.  
  7632. static GGCB dummy_ggcb;
  7633.  
  7634. static GGCB *
  7635. get_dummy_ggcb()
  7636. {
  7637.  GGCB *gp;
  7638.  
  7639.  gp = &dummy_ggcb;
  7640.  CLEAR(gp);
  7641.  
  7642.  /* Uncomment the following to see GETMAIN and FREEMAIN debugging. */
  7643.  /* gp->debug_file = stderr; */
  7644.  
  7645.  return gp;
  7646. }
  7647.  
  7648. /*===================================================================*/
  7649.  
  7650. static void
  7651. ruledump(ACCESSRULE **rulep)
  7652. {
  7653.  char       *op;
  7654.  ACCESSRULE *rule = *rulep;
  7655.  
  7656.  fprintf(stderr,"Access rule at %8.8X\n\n",rulep);
  7657.  fprintf(stderr,"number........%d\n", rule->number);
  7658.  fprintf(stderr,"hostcount.....%d\n", rule->hostcount);
  7659.  fprintf(stderr,"hosttextlen...%d\n", rule->hosttextlen);
  7660.  fprintf(stderr,"major_weight..%d\n", rule->major_weight);
  7661.  fprintf(stderr,"minor_weight..%d\n", rule->minor_weight);
  7662.  fprintf(stderr,"part1len......%d\n", rule->part1len);
  7663.  fprintf(stderr,"part2len......%d\n", rule->part2len);
  7664.  fprintf(stderr,"wildcard......%d\n", rule->wildcard);
  7665.  fprintf(stderr,"accfile.......%s\n", rule->accfile);
  7666.  fprintf(stderr,"filepart1.....%s\n", rule->filepart1);
  7667.  fprintf(stderr,"filepart2.....%s\n", rule->filepart2);
  7668.  for (op = rule->hosttext; *op; op += strlen(op)+1) {
  7669.    fprintf(stderr,"host: %s\n", op);
  7670.  }
  7671.  fprintf(stderr,"\n");
  7672. }
  7673.  
  7674. /*===================================================================*/
  7675.  
  7676. static ACCESSRULE **
  7677. get_access_rule(RRECV *R,
  7678.                 int    textlen
  7679.                )
  7680. {
  7681.  GGCB          *gp    = NULL;
  7682.  ACCESSVECTOR  *oldav = NULL;
  7683.  ACCESSVECTOR  *newav = NULL;
  7684.  ACCESSRULE   **rulep = NULL;
  7685.  int            howbig;
  7686.  int            oldcount;
  7687.  int            newcount;
  7688.  int            oldnext;
  7689.  
  7690.  gp = get_dummy_ggcb();
  7691.  
  7692.  oldav = R->accvector;
  7693.  oldcount = oldav ? oldav->rulecount : 0;
  7694.  oldnext  = oldav ? oldav->nextrule  : 0;
  7695.  
  7696.  if (!oldav || oldav->nextrule >= oldav->rulecount) {
  7697.    newcount = oldcount + 100;
  7698.    howbig = sizeof(struct accessvector)+RULEPTRSIZE*newcount;
  7699.    GETMAIN(newav, char, howbig, "access rule vector");
  7700.    if (!newav) return NULL;
  7701.    if (oldav) {
  7702.      oldcount = oldav->rulecount;
  7703.      memcpy(newav->accessrule, oldav->accessrule, RULEPTRSIZE*oldcount);
  7704.      FREEMAIN(oldav,"old access rule vector");
  7705.    }
  7706.    newav->rulecount = newcount;
  7707.    newav->nextrule  = oldnext;
  7708.    R->accvector = newav;
  7709.  }
  7710.  else {
  7711.    newav = oldav;
  7712.  }
  7713.  rulep = &newav->accessrule[newav->nextrule];
  7714.  newav->nextrule++;
  7715.  GETMAIN(*rulep,char,sizeof(ACCESSRULE)+textlen,"access rule");
  7716.  return rulep;
  7717. }
  7718.  
  7719. /*===================================================================*/
  7720.  
  7721. /* Check for wildcarding and assign weights accordingly.
  7722.  *
  7723.  * Rule Weighting, Wildcarding and Prioritization
  7724.  *
  7725.  * Since with wildcards, a path can match more than
  7726.  * one rule, with possible conflicting results, we
  7727.  * establish an algorithm for picking the appropriate rule.
  7728.  *
  7729.  * Each rule is given a weight equal to the number of
  7730.  * explicit characters in the pathspec that matches the
  7731.  * target name.  The rules with the highest weight will
  7732.  * be used - there may be more than one.  Consider
  7733.  *
  7734.  * foo.bar.baz host0
  7735.  * foo.*.baz   host1 host2 host3
  7736.  * foo.bar.*   host4 hsot5 host6
  7737.  * foo.*       host7 host8 host9
  7738.  * *.baz       host10 host11 host12
  7739.  *
  7740.  * The above rules have weight 11, 8, 8, 4, 4 respectively.
  7741.  * For file foo.bar.baz, the first rule (with weight 11)
  7742.  * supersedes, obviously.  For file foo.bar.mumble.baz,
  7743.  * all the rules except the first apply, so only the rules of
  7744.  * weight 8 (the maximum among the ones that match) will apply.
  7745.  * Now, to choose between the two rules, pick which one?
  7746.  *
  7747.  * Let's say the ones with the leftmost matching stuff
  7748.  * so that a minor weight equal to the length of the part
  7749.  * before the wildcard is used.  (subweight of 11,4,8,4,0)
  7750.  *
  7751.  * (We could sort the rules as they are loaded; then
  7752.  * the first matching rule would apply)
  7753.  *
  7754.  * So for example:
  7755.  *
  7756.  * path            major weight    minor weight
  7757.  * foo.bar.baz     11              11
  7758.  * foo.bar.*       8               8
  7759.  * foo.*.baz       8               4
  7760.  * foo.*           4               4
  7761.  * *.baz           4               0
  7762.  *
  7763.  * would be in the above order.
  7764.  */
  7765.  
  7766. static Bool
  7767. weigh_rule(ACCESSRULE *rule)
  7768. {
  7769.  Bool      rc = FALSE;
  7770.  char     *star;
  7771.  int       filelen = strlen(rule->accfile);
  7772.  
  7773.  /* Set the weights for a non-wildcard path first. */
  7774.  
  7775.  star = strchr(rule->accfile,'*'); /* Locate wildcard character */
  7776.  if (!star) {
  7777.    rule->wildcard = FALSE;
  7778.    rule->major_weight = filelen;
  7779.    rule->minor_weight = filelen;
  7780.    return TRUE;
  7781.  }
  7782.  
  7783.  rule->wildcard = TRUE;
  7784.  rule->part1len = star - rule->accfile;
  7785.  rule->part2len = filelen - rule->part1len - 1;
  7786.  rule->major_weight = filelen - 1;
  7787.  rule->minor_weight = rule->part1len;
  7788.  
  7789.  strncpy(rule->filepart1, rule->accfile, rule->part1len);
  7790.  strncpy(rule->filepart2, star + 1,      rule->part2len);
  7791.  
  7792.  if (strchr(rule->filepart2,'*')) {
  7793.    fprintf(stderr,"Multiple wildcard *'s not allowed: %s\n",
  7794.                   rule->accfile);
  7795.    return FALSE;
  7796.  }
  7797.  
  7798.  return TRUE;
  7799.  
  7800. }
  7801.  
  7802. /*===================================================================*/
  7803.  
  7804. static int
  7805. compare_rule_weights(rule1,rule2)
  7806. register const void *rule1;
  7807. register const void *rule2;
  7808. {
  7809.  register int major_weight_1 = (*(ACCESSRULE **)rule1)->major_weight;
  7810.  register int minor_weight_1 = (*(ACCESSRULE **)rule1)->minor_weight;
  7811.  register int major_weight_2 = (*(ACCESSRULE **)rule2)->major_weight;
  7812.  register int minor_weight_2 = (*(ACCESSRULE **)rule2)->minor_weight;
  7813.  
  7814.  /* This returns rules in descending order of major weight, and
  7815.   * in descending order of minor weight within that.
  7816.   */
  7817.  
  7818.  return (major_weight_2 == major_weight_1)
  7819.          ? (minor_weight_2 - minor_weight_1)
  7820.          : (major_weight_2 - major_weight_1);
  7821.  
  7822. }
  7823.  
  7824. /*===================================================================*/
  7825.  
  7826. static void
  7827. sort_rules(RRECV *R)
  7828. {
  7829.  int              rx;
  7830.  ACCESSRULE      *rule;
  7831.  
  7832.  if (R->accvector) {
  7833.    qsort(R->accvector->accessrule,R->accvector->nextrule,RULEPTRSIZE,
  7834.          compare_rule_weights);
  7835.    for (rx = 0; rx < R->accvector->nextrule; rx++) {
  7836.      rule = R->accvector->accessrule[rx];
  7837.      rule->number = rx;
  7838.    }
  7839.  }
  7840.  
  7841. }
  7842.  
  7843. /*===================================================================*/
  7844.  
  7845. static Bool
  7846. load_access_rules(RRECV *R)
  7847. {
  7848.  char        *ip;
  7849.  char        *op;
  7850.  char        *rest_of_line;
  7851.  FILE        *afp;
  7852.  ACCESSRULE  *rule;
  7853.  ACCESSRULE **rulep;
  7854.  int          rulenumber;
  7855.  int          n;
  7856.  int          hostcount;
  7857.  Bool         rc;
  7858.  char         accline  [RBUFSIZE];
  7859.  char         accfile  [RBUFSIZE];
  7860.  char         acchost  [RBUFSIZE];
  7861.  
  7862.  /* If non-socket interface, bypass the authorization check. */
  7863.  
  7864.  if (R->outfp) return TRUE;
  7865.  
  7866.  /* Load rules from the access file.  Each rule consists of a
  7867.   * pathname followed by a list of hostnames.
  7868.   * The pathname will be (dataset), EXEC:execname, or DD:file
  7869.   * - wildcards are also possible.
  7870.   */
  7871.  
  7872.  rc = TRUE;
  7873.  rulenumber = 0;
  7874.  
  7875.  afp = fopen(ACCESS_TABLE,"r");
  7876.  if (!afp) {
  7877.    perror(ACCESS_TABLE);
  7878.    fflush(stderr);
  7879.    return FALSE;
  7880.  }
  7881.  
  7882.  for (;;) {
  7883.    fgets(accline, sizeof(accline), afp);
  7884.    if (ferror(afp)) {
  7885.      fprintf(stderr,"Error reading access table %s\n",ACCESS_TABLE);
  7886.      rc = FALSE;
  7887.      break;
  7888.    }
  7889.    if (feof(afp)) break;
  7890.    uppercase_in_place(accline); /* format is: filename machine(s)   */
  7891.    ip = accline;                      /* Start scan pointer         */
  7892.    *accfile = '\0';                   /* Clear access file name     */
  7893.    sscanf(ip,"%s %n",accfile,&n);     /* Get file name, bump scan   */
  7894.    if (!*accfile) continue;           /* Ignore blank lines         */
  7895.    if (*accfile == '!' ) continue;    /* Ignore comment lines       */
  7896.    rulenumber++;
  7897.    if (strlen(accfile) > sizeof(rule->accfile)-1) {
  7898.      fprintf(stderr,"Access rule file name exceeds %d characters\n",
  7899.                     sizeof(rule->accfile)-1);
  7900.      fprintf(stderr,"Cannot load rule: %s\n\n",accline);
  7901.      rc = FALSE;
  7902.      continue;
  7903.    }
  7904.    rest_of_line = ip + n;
  7905.    rulep = get_access_rule(R,strlen(rest_of_line));
  7906.    if (!rulep) break;
  7907.    rule = *rulep;
  7908.    if (!rule) break;
  7909.    CLEAR(rule);
  7910.    rule->number = rulenumber;
  7911.    rule->hosttextlen = strlen(rest_of_line);
  7912.    strncpy(rule->accfile, accfile, sizeof(rule->accfile));
  7913.  
  7914.    /* Loop over access host ids  */
  7915.    for (ip = rest_of_line, op = rule->hosttext;;ip += n) {
  7916.      *acchost = '\0';               /* Clear word before scanf    */
  7917.      sscanf(ip,"%s %n",acchost,&n); /* Get next word, bump scan   */
  7918.      if (!*acchost) break;          /* exit loop if no more hosts */
  7919.      strcpy(op,acchost);
  7920.      op += strlen(acchost) + 1;
  7921.      rule->hostcount++;
  7922.    }
  7923.  
  7924.    if (!weigh_rule(rule)) {
  7925.      fprintf(stderr,"Cannot load rule: %s\n\n",accline);
  7926.      rc = FALSE;
  7927.      continue;
  7928.    }
  7929.  
  7930.  }
  7931.  
  7932.  (void)fclose(afp);
  7933.  
  7934.  sort_rules(R);
  7935.  
  7936.  if (R->accvector) {
  7937.    int rx;
  7938.    for (rx = 0; rx < R->accvector->nextrule; rx++) {
  7939. #ifdef ACCESS_DEBUG
  7940.      ruledump(&R->accvector->accessrule[rx]);
  7941. #endif
  7942.      rule = R->accvector->accessrule[rx];
  7943.      fprintf(stderr,"Rule %d (%d,%d): %s\n",
  7944.       rule->number,rule->major_weight,rule->minor_weight,rule->accfile);
  7945.    }
  7946.  }
  7947.  
  7948.  fflush(stderr);
  7949.  
  7950.  return rc;
  7951. }
  7952.  
  7953. /*===================================================================*/
  7954.  
  7955. static Bool
  7956. free_access_rules(RRECV *R)
  7957. {
  7958.  GGCB    *gp = NULL;
  7959.  int      i;
  7960.  if (!R->accvector) return TRUE;
  7961.  
  7962.  gp = get_dummy_ggcb();
  7963.  
  7964.  for (i = 0; i < R->accvector->nextrule; i++) {
  7965.    FREEMAIN(R->accvector->accessrule[i],"access rule");
  7966.  }
  7967.  FREEMAIN(R->accvector,"access rule vector");
  7968.  
  7969.  return TRUE;
  7970. }
  7971.  
  7972. /*===================================================================*/
  7973.  
  7974. static Bool
  7975. match(char *file,
  7976.       ACCESSRULE *rule)
  7977. {
  7978.  int   len;
  7979.  
  7980.  if (rule->wildcard) {
  7981.   len = strlen(file);
  7982.   return (rule->part1len <= len
  7983.        && rule->part2len <= len
  7984.    && !memcmp(file,                   rule->filepart1,rule->part1len)
  7985.    && !memcmp(file+len-rule->part2len,rule->filepart2,rule->part2len));
  7986.  }
  7987.  else return EQUAL(file,rule->accfile);
  7988. }
  7989.  
  7990. /*===================================================================*/
  7991.  
  7992. static Bool
  7993. check_access_rules(RRECV *R,
  7994.                    char  *fptr)
  7995. {
  7996.  char       *cp;
  7997.  char       *hostp;
  7998.  ACCESSRULE *rule;
  7999.  int         rx;
  8000.  int         this_major_weight;
  8001.  int         this_minor_weight;
  8002.  Bool        rc;
  8003.  Bool        matched;
  8004.  char        filetest [RBUFSIZE];
  8005.  
  8006.  /* If non-socket interface, bypass the authorization check. */
  8007.  
  8008.  if (R->outfp) return TRUE;
  8009.  
  8010.  /* Check that the server is allowed to return data from the file
  8011.   * specified to this routine.  Note that this could be the name of
  8012.   * an exec.  The name will be (dataset), EXEC:execname, or DD:file
  8013.   * - we look at only the first part, whitespace-delimited.
  8014.   * Entries in the file authorization table look as above.
  8015.   */
  8016.  
  8017.  rc = FALSE;
  8018.  filetest[0] = '\0';
  8019.  sscanf(fptr,"%s",filetest);
  8020.  
  8021.  if (!R->accvector) {
  8022.    fprintf(stderr,"No rules, cannot authorize: %s\n",filetest);
  8023.    fflush(stderr);
  8024.    return FALSE;
  8025.  }
  8026.  
  8027.  /* The algorithm is this:
  8028.   *
  8029.   * The rules have already been sorted in descending weight order.
  8030.   * Try each rule until one that matches the file is found, whether
  8031.   * or not the hosts match.  Save the major and minor weights of that
  8032.   * rule, because all rules with that set of weights will be tried to
  8033.   * look for a file-and-host match.  So, proceed from that point,
  8034.   * trying each rule until one of the following occurs:
  8035.   *
  8036.   * - ran out of rules with same weights - fail
  8037.   * - found a file and a host that match - succeed
  8038.   *
  8039.   * Even if a non-match is found, we keep checking because
  8040.   * there may be more than one entry in the access table
  8041.   * for this file, so that more host names can be given.
  8042.   */
  8043.  
  8044.  for (rx = 0; rx < R->accvector->nextrule; rx++) {
  8045.    rule = R->accvector->accessrule[rx];
  8046.    if (match(filetest,rule)) {
  8047.      matched = TRUE;
  8048.      this_major_weight = rule->major_weight;
  8049.      this_minor_weight = rule->minor_weight;
  8050. #ifdef ACCESS_DEBUG
  8051.      fprintf(stderr,"Rule %d (%d, %d): file name matches %s\n",
  8052.                     rule->number,rule->major_weight,rule->minor_weight,
  8053.                     rule->accfile);
  8054. #endif
  8055.      for (;rx < R->accvector->nextrule; rx++) {
  8056.        rule = R->accvector->accessrule[rx];
  8057.        if (rule->major_weight != this_major_weight
  8058.         || rule->minor_weight != this_minor_weight) break;
  8059. #ifdef ACCESS_DEBUG
  8060.        fprintf(stderr,"Trying rule %d (%d, %d): %s\n",
  8061.               rule->number,rule->major_weight, rule->minor_weight,
  8062.               rule->accfile);
  8063. #endif
  8064.        if (!matched && !match(filetest,rule)) continue;
  8065.        matched = FALSE;
  8066.        if (!*rule->hosttext) {
  8067. #ifdef ACCESS_DEBUG
  8068.          fprintf(stderr,"This rule matches for all host names\n");
  8069. #endif
  8070.          rc = TRUE;
  8071.          break;
  8072.        }
  8073.        else {
  8074.          for (hostp=rule->hosttext; *hostp; hostp+=strlen(hostp)+1) {
  8075.            if (EQUAL(R->hostname,hostp)
  8076.             || EQUAL(R->hosttest,hostp)) {   /* if hostname matches */
  8077. #ifdef ACCESS_DEBUG
  8078.              fprintf(stderr,"This rule matches host name %s\n",hostp);
  8079. #endif
  8080.              rc = TRUE;
  8081.              break;
  8082.            }
  8083.          }
  8084.          if (rc) break;
  8085.        }
  8086.      }       /* end for */
  8087.      break;  /* at end of this, we either got it or we don't */
  8088.    }         /* end if match */
  8089.  }           /* end for */
  8090.  
  8091.  if (!rc) {
  8092.    fprintf(stderr,"Not authorized from %s: '%s'\n",
  8093.                   R->hosttest, filetest);
  8094.  }
  8095.  
  8096.  fflush(stderr);
  8097.  
  8098.  return rc;
  8099. }
  8100.  
  8101. /*===================================================================*/
  8102.  
  8103. Bool
  8104. GGacces(RRECV  *R,
  8105.         ACCREQ  req
  8106.        )
  8107. {
  8108.  
  8109.  switch (req) {
  8110.    case ACCESS_LOAD:  return load_access_rules(R);
  8111.    case ACCESS_CHECK: return check_access_rules(R,R->fileptr);
  8112.    case ACCESS_FREE:  return free_access_rules(R);
  8113.  }
  8114.  
  8115. }
  8116.  
  8117. ./ ADD NAME=GGALLOC
  8118.  
  8119.  /********************************************************************/
  8120.  /*                                                                  */
  8121.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  8122.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  8123.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  8124.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  8125.  /*                                                                  */
  8126.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  8127.  /* including the implied warranties of merchantability and fitness, */
  8128.  /* are expressly denied.                                            */
  8129.  /*                                                                  */
  8130.  /* Provided this copyright notice is included, this software may    */
  8131.  /* be freely distributed and not offered for sale.                  */
  8132.  /*                                                                  */
  8133.  /* Changes or modifications may be made and used only by the maker  */
  8134.  /* of same, and not further distributed.  Such modifications should */
  8135.  /* be mailed to the author for consideration for addition to the    */
  8136.  /* software and incorporation in subsequent releases.               */
  8137.  /*                                                                  */
  8138.  /********************************************************************/
  8139.  
  8140. #pragma  csect(code,  "GG@ALLOC")
  8141. #pragma  csect(static,"GG$ALLOC")
  8142. #include "gg.h"
  8143. #include "ggsvc99.h"
  8144.  
  8145. /****** Allocate a data set. *****************************************/
  8146.  
  8147. DSTYPE
  8148. GGalloc(dsname,ddname,wanted_type,nitems)
  8149. char   *dsname;
  8150. char   *ddname;
  8151. DSTYPE  wanted_type;
  8152. int     nitems;
  8153. {
  8154.  int             i;
  8155.  int             rc;
  8156.  DSTYPE          return_type;
  8157.  Bool            try_new;
  8158.  short           primary_allocation   ;
  8159.  short           secondary_allocation ;
  8160.  short           directory_blocks     ;
  8161.  short           dsorg                ;
  8162.  __S99parms      stuff99; /* No "struct", despite manual */
  8163.  TEXTUNIT       *tu [17];
  8164.  TEXTUNIT        tu_dsn;
  8165.  TEXTUNIT        tu_ddn;
  8166.  TEXTUNIT        tu_member;
  8167.  TEXTUNIT        tu_stat;
  8168.  TEXTUNIT        tu_disp;
  8169.  TEXTUNIT        tu_perm;
  8170.  TEXTUNIT        tu_rtddn;
  8171.  TEXTUNIT        tu_rtorg;
  8172.  TEXTUNIT        tu_block;
  8173.  TEXTUNIT        tu_prime;
  8174.  TEXTUNIT        tu_sec;
  8175.  TEXTUNIT        tu_dir;
  8176.  TEXTUNIT        tu_recfm;
  8177.  TEXTUNIT        tu_lrecl;
  8178.  TEXTUNIT        tu_blksz;
  8179.  TEXTUNIT        tu_dsorg;
  8180.  char           *lparp;
  8181.  char           *rparp;
  8182.  FILE           *mfile;
  8183.  char            dsnseq [81];
  8184.  char            member [81];
  8185.  char            what_to_open [81];
  8186.  
  8187.  try_new = FALSE;
  8188.  
  8189.  memset((char *)&stuff99,0,sizeof(__S99parms));
  8190.  
  8191.  strcpy(member,"");
  8192.  strcpy(dsnseq,dsname);
  8193.  lparp = strchr(dsnseq,'(');
  8194.  rparp = strchr(dsnseq,')');
  8195.  if (lparp && rparp && (lparp < rparp) && (*(rparp+1) == '\0')) {
  8196.    *lparp = '\0';            /* makes dsnseq the seq part only */
  8197.    *rparp = '\0';            /* turns member into a string     */
  8198.    strcpy(member, lparp+1);
  8199.    wanted_type = PDS;
  8200.  }
  8201.  
  8202.  for (;;) {
  8203.  
  8204.    stuff99.__S99RBLN   = 20;
  8205.    stuff99.__S99VERB   = S99VRBAL;
  8206.    stuff99.__S99FLAG1  = S99NOCNV << 8;
  8207.    stuff99.__S99ERROR  = 0;
  8208.    stuff99.__S99INFO   = 0;
  8209.    stuff99.__S99TXTPP  = tu;
  8210.    stuff99.__S99FLAG2  = 0;
  8211.  
  8212.    i = 0;
  8213.  
  8214.    tu[i++] = &tu_dsn;
  8215.  
  8216.    tu_dsn.key        = DALDSNAM;
  8217.    tu_dsn.num        = 1;
  8218.    tu_dsn.ent.len    = strlen(dsnseq);
  8219.    copy_uppercase(tu_dsn.ent.prm,dsnseq);
  8220.  
  8221.    tu[i++] = &tu_stat;
  8222.  
  8223.    tu_stat.key      = DALSTATS;
  8224.    tu_stat.num      = 1;
  8225.    tu_stat.ent.len  = 1;
  8226.    *tu_stat.ent.prm = (try_new ? NEW : SHR);
  8227.  
  8228.    tu[i++] = &tu_disp;
  8229.  
  8230.    tu_disp.key      = DALNDISP;
  8231.    tu_disp.num      = 1;
  8232.    tu_disp.ent.len  = 1;
  8233.    *tu_disp.ent.prm = (try_new ? CATLG : KEEP);
  8234.  
  8235.    tu[i++] = &tu_rtorg;
  8236.  
  8237.    tu_rtorg.key     = DALRTORG;
  8238.    tu_rtorg.num     = 1;
  8239.    tu_rtorg.ent.len = 2;
  8240.  
  8241.    if (*member) {
  8242.  
  8243.      tu[i++] = &tu_member;
  8244.  
  8245.      tu_member.key     = DALMEMBR;
  8246.      tu_member.num     = 1;
  8247.      tu_member.ent.len = strlen(member);
  8248.      copy_uppercase(tu_member.ent.prm,member);
  8249.  
  8250.    }
  8251.  
  8252.    if (ddname && *ddname) {
  8253.  
  8254.      tu[i++] = &tu_ddn;
  8255.  
  8256.      tu_ddn.key     = DALDDNAM;
  8257.      tu_ddn.num     = 1;
  8258.      tu_ddn.ent.len = strlen(ddname);
  8259.      copy_uppercase(tu_ddn.ent.prm,ddname);
  8260.  
  8261.      tu[i++] = &tu_perm;
  8262.  
  8263.      tu_perm.key     = DALPERMA;
  8264.      tu_perm.num     = 0;
  8265.  
  8266.    }
  8267.    else {
  8268.  
  8269.      tu[i++] = &tu_rtddn;
  8270.  
  8271.      tu_rtddn.key     = DALRTDDN;
  8272.      tu_rtddn.num     = 1;
  8273.      tu_rtddn.ent.len = 8;
  8274.      memset(tu_rtddn.ent.prm,' ',8);
  8275.  
  8276.    }
  8277.  
  8278.    if (try_new) {
  8279.  
  8280.      switch (wanted_type) {
  8281.        case PDS:
  8282.                  primary_allocation   = (short)nitems;
  8283.                  secondary_allocation = primary_allocation;
  8284.                  directory_blocks     = ((short)nitems/(12*36)+1) * 36;
  8285.                  dsorg                = DSORG_PO;
  8286.                  break;
  8287.        case SEQ:
  8288.        default:
  8289.                  primary_allocation   = (short)nitems;
  8290.                  secondary_allocation = primary_allocation;
  8291.                  directory_blocks     = 0;
  8292.                  dsorg                = DSORG_PS;
  8293.                  break;
  8294.      }
  8295.  
  8296.      tu[i++] = &tu_block;
  8297.  
  8298.      tu_block.key     = DALBLKLN;
  8299.      tu_block.num     = 1;
  8300.      tu_block.ent.len = 3;
  8301.      memset(tu_block.ent.prm,0,3);
  8302.      *(short *)(tu_block.ent.prm+1) = 6233;
  8303.  
  8304.      tu[i++] = &tu_prime;
  8305.  
  8306.      tu_prime.key     = DALPRIME;
  8307.      tu_prime.num     = 1;
  8308.      tu_prime.ent.len = 3;
  8309.      memset(tu_prime.ent.prm,0,3);
  8310.      *(short *)(tu_prime.ent.prm+1) = primary_allocation;
  8311.  
  8312.      tu[i++] = &tu_sec;
  8313.  
  8314.      tu_sec.key     = DALSECND;
  8315.      tu_sec.num     = 1;
  8316.      tu_sec.ent.len = 3;
  8317.      memset(tu_sec.ent.prm,0,3);
  8318.      *(short *)(tu_sec.ent.prm+1) = secondary_allocation;
  8319.  
  8320.      tu[i++] = &tu_dir;
  8321.  
  8322.      tu_dir.key     = DALDIR;
  8323.      tu_dir.num     = 1;
  8324.      tu_dir.ent.len = 3;
  8325.      memset(tu_dir.ent.prm,0,3);
  8326.      *(short *)(tu_dir.ent.prm+1) = directory_blocks;
  8327.  
  8328.      tu[i++] = &tu_recfm;
  8329.  
  8330.      tu_recfm.key        = DALRECFM;
  8331.      tu_recfm.num        = 1;
  8332.      tu_recfm.ent.len    = 1;
  8333.      *tu_recfm.ent.prm   = RECFM_VB;
  8334.  
  8335.      tu[i++] = &tu_lrecl;
  8336.  
  8337.      tu_lrecl.key        = DALLRECL;
  8338.      tu_lrecl.num        = 1;
  8339.      tu_lrecl.ent.len    = 2;
  8340.      *(short *)tu_lrecl.ent.prm   = 259;
  8341.  
  8342.      tu[i++] = &tu_blksz;
  8343.  
  8344.      tu_blksz.key        = DALBLKSZ;
  8345.      tu_blksz.num        = 1;
  8346.      tu_blksz.ent.len    = 2;
  8347.      *(short *)tu_blksz.ent.prm   = 6233;
  8348.  
  8349.      tu[i++] = &tu_dsorg;
  8350.  
  8351.      tu_dsorg.key        = DALDSORG;
  8352.      tu_dsorg.num        = 1;
  8353.      tu_dsorg.ent.len    = 2;
  8354.      *(short *)tu_dsorg.ent.prm   = dsorg;
  8355.  
  8356.    }
  8357.  
  8358.    tu[i] = (void *)0x80000000;
  8359.  
  8360.    rc = svc99(&stuff99);
  8361.  
  8362.    if (rc == 0) {
  8363.      if (!(ddname && *ddname)) {
  8364.        memcpy(ddname,(char *)tu_rtddn.ent.prm,8);
  8365.        *(ddname+8) = ' ';
  8366.        *(strchr(ddname,' ')) = '\0';
  8367.      }
  8368.      switch (tu_rtorg.ent.prm[0]) {
  8369.        case 0x40:  return_type = SEQ; break;
  8370.        case 0x02:  return_type = PDS; break;
  8371.        default:    return_type = UNK; break;
  8372.      }
  8373.      if (wanted_type == SEQ && return_type != SEQ) {
  8374.        fprintf(stderr,"%s: not a sequential data set\n",dsname);
  8375.      }
  8376.      if (wanted_type == PDS && return_type != PDS) {
  8377.        fprintf(stderr,"%s: not a partitioned data set\n",dsname);
  8378.      }
  8379.      if (return_type == PDS && *member) return SEQ;
  8380.      else return return_type;
  8381.    }
  8382.    else if (!try_new && nitems != 0 && stuff99.__S99ERROR == 0x1708) {
  8383.     try_new = TRUE;
  8384.     continue;
  8385.    }
  8386.    else {
  8387.      GGdfail(rc,&stuff99);
  8388.      return UNK;
  8389.    }
  8390.  }
  8391. }
  8392.  
  8393. ./ ADD NAME=GGASVC
  8394.  
  8395.  /********************************************************************/
  8396.  /*                                                                  */
  8397.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  8398.  /*                                                                  */
  8399.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  8400.  /* including the implied warranties of merchantability and fitness, */
  8401.  /* are expressly denied.                                            */
  8402.  /*                                                                  */
  8403.  /* Provided this copyright notice is included, this software may    */
  8404.  /* be freely distributed and not offered for sale.                  */
  8405.  /*                                                                  */
  8406.  /* Changes or modifications may be made and used only by the maker  */
  8407.  /* of same, and not further distributed.  Such modifications should */
  8408.  /* be mailed to the author for consideration for addition to the    */
  8409.  /* software and incorporation in subsequent releases.               */
  8410.  /*                                                                  */
  8411.  /********************************************************************/
  8412.  
  8413. #pragma  csect(code,  "GG@ASVC")
  8414. #pragma  csect(static,"GG$ASVC")
  8415.  
  8416. #include "gg.h"
  8417. #include "ggsvc.h"
  8418.  
  8419. #define HEX(A)      0x##A
  8420. #define I4(A,B,C,D) HEX(A), HEX(B), HEX(C), HEX(D)
  8421. #define I2(A,B)     HEX(A), HEX(B)
  8422.  
  8423. /*
  8424.  *  Usage:   SVC(SVC_NUMBER   svcnumber,
  8425.  *               SVC_REGISTER register15,
  8426.  *               SVC_REGISTER register0,
  8427.  *               SVC_REGISTER register1)
  8428.  *
  8429.  * This routine invokes the specified SVC with the specified contents
  8430.  * of registers 15, 0 and 1, and fills in the returned values of those
  8431.  * registers on return from the SVC.  That is why the caller must pass
  8432.  * the register words by reference.
  8433.  */
  8434.  
  8435. void
  8436. GGasvc(SVC_NUMBER     num,
  8437.        SVC_REGISTER  *r15,
  8438.        SVC_REGISTER  *r00,
  8439.        SVC_REGISTER  *r01
  8440.       )
  8441. {
  8442.  void               (*svccode)();
  8443.  
  8444. static char  assembler_code[] = {
  8445.    I4(90,ec,d0,0c), /* 0000       STM  14,12,12(13)  */
  8446.    I2(18,3f),       /* 0004       LR   3,15          */
  8447.    I4(98,47,10,00), /* 0006       LM   4,7,0(1)      */
  8448.    I4(58,f0,50,00), /* 000A       L    15,0(,5)      */
  8449.    I4(58,00,60,00), /* 000E       L    0,0(,6)       */
  8450.    I4(58,10,70,00), /* 0012       L    1,0(,7)       */
  8451.    I4(44,40,30,2c), /* 0016       EX   4,EXSVC       */
  8452.    I4(50,f0,50,00), /* 001A       ST   15,0(,5)      */
  8453.    I4(50,00,60,00), /* 001E       ST   0,0(,6)       */
  8454.    I4(50,10,70,00), /* 0022       ST   1,0(,7)       */
  8455.    I4(98,ec,d0,0c), /* 0026       LM   14,12,12(13)  */
  8456.    I2(07,fe),       /* 002A       BR   14            */
  8457.    I2(0a,00)        /* 002C EXSVC SVC  0             */
  8458.   };
  8459.  
  8460.  svccode = (void (*)()) assembler_code;
  8461.  (*svccode)(num,r15,r00,r01);
  8462.  
  8463.  return;
  8464. }
  8465.  
  8466. ./ ADD NAME=GGBARF
  8467.  
  8468.  /********************************************************************/
  8469.  /*                                                                  */
  8470.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  8471.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  8472.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  8473.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  8474.  /*                                                                  */
  8475.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  8476.  /* including the implied warranties of merchantability and fitness, */
  8477.  /* are expressly denied.                                            */
  8478.  /*                                                                  */
  8479.  /* Provided this copyright notice is included, this software may    */
  8480.  /* be freely distributed and not offered for sale.                  */
  8481.  /*                                                                  */
  8482.  /* Changes or modifications may be made and used only by the maker  */
  8483.  /* of same, and not further distributed.  Such modifications should */
  8484.  /* be mailed to the author for consideration for addition to the    */
  8485.  /* software and incorporation in subsequent releases.               */
  8486.  /*                                                                  */
  8487.  /********************************************************************/
  8488.  
  8489. #pragma  csect(code,  "GG@BARF")
  8490. #pragma  csect(static,"GG$BARF")
  8491.  
  8492. #include "gg.h"
  8493.  
  8494. void
  8495. GGbarf(RECV  *R,
  8496.        char  *message)
  8497. {
  8498.  char        temp [257];
  8499.  
  8500.  if (!R->outfp) fprintf(stderr,"Barfing: %s\n", message);
  8501.  
  8502.  if (R->gopherplus) {
  8503.    if (!GGouts(R,"--1<" GOPHER_ADMIN ">", OUT_PLUS)) return;
  8504.    if (!GGouts(R,message,                 NO_VALUE)) return;
  8505.  }
  8506.  else {
  8507.    /* the number should be 3 (ERROR) but some clients may not show it
  8508.     *             |
  8509.     *             V
  8510.     */
  8511.    sprintf(temp, "1%s.\t0\t0\t0", message);
  8512.    (void)GGouts(R,temp,NO_VALUE);
  8513.  }
  8514.  return;
  8515. }
  8516.  
  8517. ./ ADD NAME=GGBIN
  8518.  
  8519.  /********************************************************************/
  8520.  /*                                                                  */
  8521.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  8522.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  8523.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  8524.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  8525.  /*                                                                  */
  8526.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  8527.  /* including the implied warranties of merchantability and fitness, */
  8528.  /* are expressly denied.                                            */
  8529.  /*                                                                  */
  8530.  /* Provided this copyright notice is included, this software may    */
  8531.  /* be freely distributed and not offered for sale.                  */
  8532.  /*                                                                  */
  8533.  /* Changes or modifications may be made and used only by the maker  */
  8534.  /* of same, and not further distributed.  Such modifications should */
  8535.  /* be mailed to the author for consideration for addition to the    */
  8536.  /* software and incorporation in subsequent releases.               */
  8537.  /*                                                                  */
  8538.  /********************************************************************/
  8539.  
  8540. #pragma  csect(code,  "GG@BIN  ")
  8541. #pragma  csect(static,"GG$BIN  ")
  8542. #include "gg.h"
  8543.  
  8544. /****** Display a binary file retrieved from the server. *************/
  8545.  
  8546. Bool
  8547. GGbin(gp,ip,how)
  8548. RGGCB     *gp;
  8549. RINFO     *ip;
  8550. GOHOW      how;
  8551. {
  8552.  TEXTHDR  *texthdrp;
  8553.  char      title [81];
  8554.  
  8555.  switch (how) {
  8556.    case AS_NOTHING: return;
  8557.    default:         break;
  8558.  }
  8559.  
  8560.  texthdrp = (ip ? &ip->thdr : &gp->thdr);
  8561.  
  8562.  if (!ip) sprintf(title, "GopherServer:%s ",gp->ggserver);
  8563.  else     strncpy(title, ip->desc, sizeof(title));
  8564.  
  8565.  GGview(gp,ip,texthdrp,title);
  8566.  
  8567.  return;
  8568. }
  8569.  
  8570. ./ ADD NAME=GGBKMGR
  8571.  
  8572.  /********************************************************************/
  8573.  /*                                                                  */
  8574.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  8575.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  8576.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  8577.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  8578.  /*                                                                  */
  8579.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  8580.  /* including the implied warranties of merchantability and fitness, */
  8581.  /* are expressly denied.                                            */
  8582.  /*                                                                  */
  8583.  /* Provided this copyright notice is included, this software may    */
  8584.  /* be freely distributed and not offered for sale.                  */
  8585.  /*                                                                  */
  8586.  /* Changes or modifications may be made and used only by the maker  */
  8587.  /* of same, and not further distributed.  Such modifications should */
  8588.  /* be mailed to the author for consideration for addition to the    */
  8589.  /* software and incorporation in subsequent releases.               */
  8590.  /*                                                                  */
  8591.  /********************************************************************/
  8592.  
  8593. #pragma  csect(code,  "GG@BKMGR")
  8594. #pragma  csect(static,"GG$BKMGR")
  8595. #include "gg.h"
  8596.  
  8597. /****** Display a BookManager (C) IBM file from the server. **********/
  8598.  
  8599. Bool
  8600. GGbkmgr(gp,ip,how)
  8601. RGGCB     *gp;
  8602. RINFO     *ip;
  8603. GOHOW      how;
  8604. {
  8605.  int       tsorc;
  8606.  Bool      ok = FALSE;
  8607.  FILE     *tempfile = NULL;
  8608.  char      ddname  [ 12];
  8609.  char      tempdsn [257];
  8610.  char      command [257];
  8611.  
  8612.  switch (how) {
  8613.    case AS_NOTHING: return;
  8614.    default:         break;
  8615.  }
  8616.  
  8617.  /* Create temporary file to hold binary BookManager data. */
  8618.  
  8619.  if (!tmpnam(tempdsn)) {
  8620.    ERR1("Could not create temporary file for BookManager");
  8621.    return FALSE;
  8622.  }
  8623.  
  8624.  strcpy(ddname,"dd:");
  8625.  
  8626.  if (GGalloc(tempdsn,ddname+3,SEQ,500) != SEQ) {
  8627.    ERR2("The temporary file %s could not be allocated.",
  8628.          tempdsn);
  8629.    return FALSE;
  8630.  }
  8631.  
  8632.  tempfile = OPEN_BOOKMANAGER_BINARY_FILE(ddname);
  8633.  if (!tempfile) {
  8634.    perror(tempdsn);
  8635.    ERR2("The temporary file %s could not be opened.", tempdsn);
  8636.    return FALSE;
  8637.  }
  8638.  
  8639.  /* Write binary text data to temporary file.              */
  8640.  
  8641.  ok = TRUE;
  8642.  
  8643.  if (ip->thdr.first_text_line) {
  8644.    gp->extract_file = tempfile;
  8645.    if (!GGxtx(gp,ip,BOOKMANAGE_IT)) {
  8646.      ERR2("Error writing to temporary BookManager file %s",tempdsn);
  8647.      ok = FALSE;
  8648.    }
  8649.  }
  8650.  else {
  8651.    ERR1("The retrieved BookManager file is empty.");
  8652.    ok = FALSE;
  8653.  }
  8654.  
  8655.  if (fclose(tempfile) < 0) {
  8656.    ERR2("The temporary BookManager file %s could not be closed.",
  8657.          tempdsn);
  8658.    return FALSE;
  8659.  }
  8660.  
  8661.  (void)GGunalc(ddname+3);
  8662.  
  8663.  if (ok) {
  8664.  
  8665.    sprintf(command,"%s BOOK(%s)",gp->mybkmgr,tempdsn);
  8666.  
  8667.    if ((tsorc = GGtso(command)) != 0) {
  8668.      ERR3("Command \"%s\" returned code %d", command, tsorc);
  8669.    }
  8670.  
  8671.    /* Remove temporary file. */
  8672.  
  8673.    if (remove(tempdsn) < 0) {
  8674.      ERR2("The temporary BookManager file %s could not be removed.",
  8675.            tempdsn);
  8676.    }
  8677.  
  8678.  }
  8679.  
  8680.  ISPF("CONTROL DISPLAY REFRESH");
  8681.  
  8682.  return ok;
  8683. }
  8684.  
  8685. ./ ADD NAME=GGCLIEN
  8686.  
  8687.  /********************************************************************/
  8688.  /*                                                                  */
  8689.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  8690.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  8691.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  8692.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  8693.  /*                                                                  */
  8694.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  8695.  /* including the implied warranties of merchantability and fitness, */
  8696.  /* are expressly denied.                                            */
  8697.  /*                                                                  */
  8698.  /* Provided this copyright notice is included, this software may    */
  8699.  /* be freely distributed and not offered for sale.                  */
  8700.  /*                                                                  */
  8701.  /* Changes or modifications may be made and used only by the maker  */
  8702.  /* of same, and not further distributed.  Such modifications should */
  8703.  /* be mailed to the author for consideration for addition to the    */
  8704.  /* software and incorporation in subsequent releases.               */
  8705.  /*                                                                  */
  8706.  /********************************************************************/
  8707.  
  8708. #ifdef SASC
  8709. #pragma  runopts(EXECOPS)
  8710. #else
  8711. #pragma  runopts(heap(8k,8k,anywhere,))
  8712. #endif
  8713.  
  8714. #pragma  csect(code,  "GG@CLIEN")
  8715. #pragma  csect(static,"GG$CLIEN")
  8716. #include "gg.h"
  8717.  
  8718. #ifdef I370
  8719. char * _style = "tso:";
  8720. #endif
  8721.  
  8722. /*********************************************************************/
  8723.  
  8724. static void
  8725. trap_ispf_command(gp,verb,action)
  8726. RGGCB            *gp;
  8727. char             *verb;
  8728. char             *action;
  8729. {
  8730.  char             zcttrunc [16];
  8731.  char             zctact   [64];
  8732.  char             zctdesc [128];
  8733.  
  8734.  if (!VPUT("ZCTVERB ",verb)) return;
  8735.  
  8736.  if (!ISPF("TBTOP ISPCMDS")) return;
  8737.  if (!ISPF("TBSCAN ISPCMDS ARGLIST(ZCTVERB)")) return;
  8738.  if (!VGET("ZCTACT ",zctact))  return;
  8739.  if (UNEQUAL(zctact,action)) {
  8740.    VGET("ZCTTRUNC ",zcttrunc);
  8741.    VGET("ZCTDESC  ",zctdesc );
  8742.    if (!ISPF("TBTOP ISPCMDS")) return;
  8743.    VPUT("ZCTACT   ",action  );
  8744.    VPUT("ZCTTRUNC ",zcttrunc);
  8745.    VPUT("ZCTDESC  ",zctdesc );
  8746.    if (!ISPF("TBADD ISPCMDS")) return;
  8747.  }
  8748.  
  8749.  return;
  8750. }
  8751.  
  8752. /*********************************************************************/
  8753.  
  8754. static Bool
  8755. go_for_it(gp,ip)
  8756. RGGCB    *gp;
  8757. RINFO    *ip;
  8758. {
  8759.  
  8760.  VGET("GGHOST ",ip->host);
  8761.  VGET("GGPATH ",ip->path);
  8762.  VGET("GGDESC ",ip->desc);
  8763.  ip->port = IGET("GGPORT ");
  8764.  ip->type = INITIAL_TYPE;
  8765.  if (!*ip->path) strcpy(ip->path,INITIAL_PATH);
  8766.  if (!*ip->host) strcpy(ip->host,INITIAL_HOST);
  8767.  if (!*ip->desc) strcpy(ip->desc,INITIAL_DESC);
  8768.  if (ip->port == 0) ip->port = INITIAL_PORT;
  8769.  *ip->bmds = '\0';
  8770.  return GGgofor(gp,ip,AS_NORMAL);
  8771.  
  8772. }
  8773.  
  8774. /*********************************************************************/
  8775.  
  8776. int
  8777. main(argc,argv)
  8778. int      argc;
  8779. char   **argv;
  8780. {
  8781.  GGCB         *gp;
  8782.  GOPHERINFO   *ip;
  8783.  CONNECTION   *sp;
  8784.  char         *p;
  8785.  int           i;
  8786.  int           exitrc;
  8787.  Bool          bypass_startup;
  8788.  GGCB          gg;
  8789.  char          ggdomain [129];
  8790.  char          ggtelnet [129];
  8791.  char          ggbkmgr  [129];
  8792.  char          zerrsm   [25];
  8793.  char          zerrlm   [ZERRLM_SIZE];
  8794.  
  8795.  exitrc = 0;
  8796.  gp = ≫
  8797.  CLEAR(gp);
  8798.  
  8799.  GETMAIN(ip, GOPHERINFO, 1, "top-level gopherinfo struct");
  8800.  if (!ip) {
  8801.    fprintf(stderr,"Not enough memory to start up GOPHER\n");
  8802.    exit(16);
  8803.  }
  8804.  
  8805.  CLEAR(ip);
  8806.  gp->ginfo = ip;
  8807.  
  8808.  for (i = 1; i < argc; i++) {
  8809.    p = argv[i];
  8810.    if (*p == '-') {
  8811.      while (*++p) {
  8812.        switch (toupper(*p)) {
  8813.          case 'T': gp->test_mode  = TRUE; break;
  8814.          case 'D': gp->debug_mode = TRUE; break;
  8815.          case 'L': gp->local_mode = TRUE; break;
  8816.          case 'Q': bypass_startup = TRUE; break;
  8817.          default:  fprintf(stderr,"GGMVS: Bad parameter flag %c\n",*p);
  8818.                    exitrc = 8;
  8819.        }
  8820.      }
  8821.    }
  8822.    else {
  8823.      fprintf(stderr,"GGMVS: Bad parameter string %s\n",p);
  8824.      exitrc = 8;
  8825.    }
  8826.  }
  8827.  
  8828.  if (gp->test_mode) __ctest(NULL);
  8829.  
  8830.  if (gp->debug_mode) {
  8831.    if (!(gp->debug_file = fopen(DEBUG_FILE,"w"))) {
  8832.      perror(DEBUG_FILE);
  8833.      exitrc = 4;
  8834.    }
  8835.  }
  8836.  
  8837.  GGclrtx(gp,NULL); /* Clear text */
  8838.  GGclrtx(gp,ip);   /* Clear text */
  8839.  
  8840.  /* These may be overridden from gopherrc. */
  8841.  
  8842.  gp->myport   = SERV_TCP_PORT;
  8843.  gp->mytelnet = TELNET_COMMAND_NAME;
  8844.  gp->mybkmgr  = BOOKMGR_COMMAND_NAME;
  8845.  gp->mydomain = MY_DOMAIN_SUFFIX;
  8846.  
  8847.  sp = &gp->gopher_connection;
  8848.  
  8849.  GETMAIN(sp->server_buf,    char,SERVER_BUF_MSGSIZE+4,"server buffer");
  8850.  GETMAIN(sp->client_buf,    char,CLIENT_BUF_MSGSIZE+4,"client buffer");
  8851.  GETMAIN(gp->gopher_command,char,CLIENT_BUF_MSGSIZE+4,"gopher command");
  8852.  
  8853. #ifdef FETCH
  8854.  gp->isplink_pointer = (int (*) ())fetch("ISPLINK");
  8855.  gp->ispexec_pointer = (int (*) ())fetch("ISPEXEC");
  8856. #endif
  8857.  
  8858.  if (!ISPF("CONTROL ERRORS RETURN")) exitrc = 20;
  8859.  
  8860.  else {
  8861.  
  8862.    exitrc = 0;
  8863.    trap_ispf_command(gp,"RFIND","&YRFIND");  /* enable RFIND */
  8864.  
  8865.    ISPF("TBGET GOPHERVT");    /* get Gopher startup variables */
  8866.    ISPF("TBCLOSE GOPHERVT");  /* ... in case of split screen gophers */
  8867.  
  8868.    VGET("GGDOMAIN ",ggdomain);
  8869.    VGET("GGTELNET ",ggtelnet);
  8870.    VGET("GGBKMGR  ",ggbkmgr );
  8871.    if (*ggdomain) gp->mydomain = ggdomain;
  8872.    if (*ggtelnet) gp->mytelnet = ggtelnet;
  8873.    if (*ggbkmgr)  gp->mybkmgr  = ggbkmgr;
  8874.  
  8875.    GGsopt(gp,OPTION_ALL);      /* set options */
  8876.  
  8877.    if (bypass_startup) {       /* use values put in table by exec */
  8878.      (void)go_for_it(gp,ip);
  8879.    }
  8880.    else {
  8881.      VPUT("ZCMD ","");
  8882.      while (GGdispl(gp,"GGM     ") == 0
  8883.          && !gp->quit
  8884.          && !go_for_it(gp,ip)) ;
  8885.    }
  8886.  }
  8887.  
  8888.  if (gp->setmsg) {
  8889.    VGET("ZERRSM ",zerrsm);
  8890.    VGET("ZERRLM ",zerrlm);
  8891.    fprintf(stderr,"%s: %s\n",zerrsm,zerrlm);
  8892.    gp->setmsg = FALSE;
  8893.  }
  8894.  
  8895.  if (sp->connected_to_server) {
  8896.    GGdisc(gp,sp);            /* disconnect from gopher server */
  8897.  }
  8898.  
  8899.  FREEMAIN(gp->gopher_command,"gopher command");
  8900.  FREEMAIN(sp->server_buf,    "server buffer");
  8901.  FREEMAIN(sp->client_buf,    "client buffer");
  8902.  FREEMAIN(ip,                "top-level gopherinfo struct");
  8903.  
  8904.  #define FINAL_CLOSE(A,B) \
  8905.    if (A) { \
  8906.             if (fclose(A) < 0) fprintf(stderr,B); \
  8907.           }
  8908.  
  8909.  FINAL_CLOSE(gp->debug_file, "Error closing debug file\n");
  8910.  
  8911.  exit(exitrc);
  8912. }
  8913.  
  8914. ./ ADD NAME=GGCLRTX
  8915.  
  8916.  /********************************************************************/
  8917.  /*                                                                  */
  8918.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  8919.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  8920.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  8921.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  8922.  /*                                                                  */
  8923.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  8924.  /* including the implied warranties of merchantability and fitness, */
  8925.  /* are expressly denied.                                            */
  8926.  /*                                                                  */
  8927.  /* Provided this copyright notice is included, this software may    */
  8928.  /* be freely distributed and not offered for sale.                  */
  8929.  /*                                                                  */
  8930.  /* Changes or modifications may be made and used only by the maker  */
  8931.  /* of same, and not further distributed.  Such modifications should */
  8932.  /* be mailed to the author for consideration for addition to the    */
  8933.  /* software and incorporation in subsequent releases.               */
  8934.  /*                                                                  */
  8935.  /********************************************************************/
  8936.  
  8937. #pragma  csect(code,  "GG@CLRTX")
  8938. #pragma  csect(static,"GG$CLRTX")
  8939. #include "gg.h"
  8940.  
  8941. /****** Clear text. **************************************************/
  8942.  
  8943. void
  8944. GGclrtx(gp,ip)
  8945. RGGCB  *gp;
  8946. RINFO  *ip;
  8947. {
  8948.  register TEXTHDR   *thp;
  8949.  register TEXTLINE  *tp1;
  8950.  register TEXTLINE  *tp2;
  8951.  
  8952.  /* If info is not specified, use main ggcb, else info's text */
  8953.  
  8954.  thp = (ip ? &ip->thdr : &gp->thdr);
  8955.  
  8956.  tp1 = thp->first_text_line;
  8957.  while (tp1) {
  8958.   tp2 = tp1->next;
  8959.   FREEMAIN(tp1,"text line");
  8960.   tp1 = tp2;
  8961.  }
  8962.  
  8963.  CLEAR(thp);
  8964.  
  8965.  return;
  8966.  
  8967. }
  8968.  
  8969. ./ ADD NAME=GGCONN
  8970.  
  8971.  /********************************************************************/
  8972.  /*                                                                  */
  8973.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  8974.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  8975.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  8976.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  8977.  /*                                                                  */
  8978.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  8979.  /* including the implied warranties of merchantability and fitness, */
  8980.  /* are expressly denied.                                            */
  8981.  /*                                                                  */
  8982.  /* Provided this copyright notice is included, this software may    */
  8983.  /* be freely distributed and not offered for sale.                  */
  8984.  /*                                                                  */
  8985.  /* Changes or modifications may be made and used only by the maker  */
  8986.  /* of same, and not further distributed.  Such modifications should */
  8987.  /* be mailed to the author for consideration for addition to the    */
  8988.  /* software and incorporation in subsequent releases.               */
  8989.  /*                                                                  */
  8990.  /********************************************************************/
  8991.  
  8992. #pragma  csect(code,  "GG@CONN ")
  8993. #pragma  csect(static,"GG$CONN ")
  8994. #include "gg.h"
  8995.  
  8996. /****** Get client hostname and IP address. **************************/
  8997.  
  8998. static Bool
  8999. get_client_hostname(gp)
  9000. RGGCB              *gp;
  9001. {
  9002.  struct hostent    *client_hp;
  9003.  int                gethostnamerc;
  9004.  int                hostlen;
  9005.  int                domslen;
  9006.  
  9007.  gethostnamerc = gethostname(gp->client_hostname,MAXHOSTNAMELEN);
  9008.  if (gethostnamerc < 0) {
  9009.    fprintf(stderr,"GGMVS: gethostname() failed, don't know my name\n");
  9010.    return FALSE;
  9011.  }
  9012.  
  9013. #ifdef APPEND_DOMAIN_NAME_TO_SELF
  9014.  
  9015.  hostlen = strlen(gp->client_hostname);
  9016.  domslen = strlen(gp->mydomain);
  9017.  if (hostlen <= domslen ||
  9018.     memcmp(gp->client_hostname+hostlen-domslen,gp->mydomain,domslen)) {
  9019.    strncat(gp->client_hostname,gp->mydomain,domslen);
  9020.  }
  9021.  
  9022. #endif
  9023.  
  9024.  uppercase_in_place(gp->client_hostname);
  9025.  
  9026.  client_hp = gethostbyname(gp->client_hostname);
  9027.  if (!client_hp) {
  9028.    fprintf(stderr,
  9029.            "GGMVS: gethostbyname(%s) failed, can't get my name\n",
  9030.            gp->client_hostname);
  9031.    return FALSE;
  9032.  }
  9033.  
  9034.  strcpy(gp->ggclient,gp->client_hostname);
  9035.  strcpy(gp->client_hostname, client_hp->h_name);
  9036.  gp->client_ip_address = *(IPADDRESS *)client_hp->h_addr;
  9037.  
  9038.  return TRUE;
  9039.  
  9040. }
  9041.  
  9042. /****** Connect to news server. **************************************/
  9043.  
  9044. Bool
  9045. GGconn(gp,sp)
  9046. RGGCB *gp;
  9047. RCONN *sp;
  9048. {
  9049.  char              *lp;
  9050.  char              *cp;
  9051.  RECV              *R;
  9052.  struct hostent    *server_hp;
  9053.  struct sockaddr_in bindsock;
  9054.  struct sockaddr_in consock;
  9055.  int                bindrc;
  9056.  int                connrc;
  9057.  int                ip_part_1;
  9058.  int                ip_part_2;
  9059.  int                ip_part_3;
  9060.  int                ip_part_4;
  9061.  char               tempdsn [L_tmpnam];
  9062.  
  9063.  if (sp->connected_to_server) {
  9064.    GGdisc(gp,sp);         /* Disconnect from gopher server */
  9065.  }
  9066.  
  9067.  sp->closing_connection = FALSE;
  9068.  sp->buf_index          = -1;
  9069.  sp->bytes_returned     = 0;
  9070.  sp->receiving_text     = FALSE;
  9071.  sp->is_ftp             = FALSE;
  9072.  
  9073.  if (!*gp->ggserver) {
  9074.    ERR1(
  9075.    "No host server defined in Gopher menu.  Cannot make a connection.");
  9076.    return FALSE;
  9077.  }
  9078.  
  9079.  uppercase_in_place(gp->ggserver);
  9080.  
  9081.  /* If server is "local hack", then establish local mode,
  9082.   * open temporary file and return.
  9083.   */
  9084.  
  9085.  if (!strcmp(gp->ggserver, LOCAL_HOST_FROB)) {
  9086.  
  9087.    if (gp->ginfo->port != GOPHER_PORT_NUMBER) {
  9088.      ERR3("Server name %s is permitted only with port number %d.",
  9089.           LOCAL_HOST_FROB, GOPHER_PORT_NUMBER);
  9090.      return FALSE;
  9091.    }
  9092.  
  9093.    GETMAIN(gp->recvp, RECV, 1, "local recv struct");
  9094.    if (!gp->recvp) {
  9095.      CRIT1("Can't get memory for local host struct");
  9096.      return FALSE;
  9097.    }
  9098.    R = gp->recvp;
  9099.    CLEAR(R);
  9100.  
  9101.    R->myport   = gp->myport;
  9102.    R->mytelnet = gp->mytelnet;
  9103.    R->mybkmgr  = gp->mybkmgr;
  9104.    R->mydomain = gp->mydomain;
  9105.  
  9106.    if (!tmpnam(tempdsn)) {
  9107.      CRIT1("Can't create temporary file for local access");
  9108.      return FALSE;
  9109.    }
  9110.  
  9111.    /* Create temporary file for writing and reading. */
  9112.  
  9113.    R->outfp = fopen(tempdsn,"w+,type=memory");
  9114.    if (!R->outfp) {
  9115.      perror(tempdsn);
  9116.      CRIT1("Can't open temporary file for local access");
  9117.      return FALSE;
  9118.    }
  9119.  
  9120.    sp->connected_to_server = TRUE;
  9121.    sp->time_to_go_home     = FALSE;
  9122.    sp->connection_broken   = FALSE;
  9123.  
  9124.    GGesrvr(gp,sp);   /* Clean up any stray responses from server. */
  9125.  
  9126.    return TRUE;
  9127.  }
  9128.  
  9129.  /* Disallow network connections if started up in local mode. */
  9130.  
  9131.  if (gp->local_mode) {
  9132.    ERR1("Network connections are not allowed in local mode.");
  9133.    return FALSE;
  9134.  }
  9135.  
  9136.  /* Determine the local path name. Do only if making net conn. */
  9137.  
  9138.  if (!*gp->client_hostname) {
  9139.    if (!get_client_hostname(gp)) return FALSE;
  9140.  }
  9141.  
  9142.  /* Get server name and address.  */
  9143.  
  9144.  if (strchr(gp->ggserver,'.') &&
  9145.      gp->ggserver[strspn(gp->ggserver,".0123456789")] == '\0') {
  9146.    ip_part_1 = ip_part_2 = ip_part_3 = ip_part_4 = 32767;
  9147.    strcpy(gp->server_hostname, gp->ggserver);
  9148.    strcpy(sp->server_hostname, gp->ggserver);
  9149.    sscanf(gp->ggserver,"%d.%d.%d.%d",
  9150.                        &ip_part_1,&ip_part_2,&ip_part_3,&ip_part_4);
  9151.    if (ip_part_1 > 255 ||
  9152.        ip_part_2 > 255 ||
  9153.        ip_part_3 > 255 ||
  9154.        ip_part_4 > 255) {
  9155.      ERR2("Syntax error in server network address: %s", gp->ggserver);
  9156.      return FALSE;
  9157.    }
  9158.    gp->server_ip_address = (IPADDRESS) ((ip_part_1 << 24) +
  9159.                                         (ip_part_2 << 16) +
  9160.                                         (ip_part_3 <<  8) +
  9161.                                         (ip_part_4      ));
  9162.  }
  9163.  else {
  9164.    server_hp = gethostbyname(gp->ggserver);
  9165.    if (!server_hp) {
  9166.      ERR2(
  9167. "Unknown host %s - gethostbyname() could not resolve the server name.",
  9168.           gp->ggserver);
  9169.      return FALSE;
  9170.    }
  9171.    strcpy(gp->server_hostname, server_hp->h_name);
  9172.    strcpy(sp->server_hostname, server_hp->h_name);
  9173.    gp->server_ip_address = *(IPADDRESS *)server_hp->h_addr;
  9174.  }
  9175.  
  9176.  SPRINTF_IP_ADDRESS(gp->server_ip_addrstr, gp->server_ip_address);
  9177.  SPRINTF_IP_ADDRESS(gp->client_ip_addrstr, gp->client_ip_address);
  9178.  
  9179.  VPUT("GGSERVER ",gp->ggserver);
  9180.  VPUT("GGCLIENT ",gp->ggclient);
  9181.  VPUT("GGSERVIP ",gp->server_ip_addrstr);
  9182.  VPUT("GGCLIEIP ",gp->client_ip_addrstr);
  9183.  
  9184.  consock.sin_family       = AF_INET;
  9185.  consock.sin_port         = htons(gp->ginfo->port);
  9186.  consock.sin_addr.s_addr  = gp->server_ip_address;
  9187.  
  9188.  bindsock.sin_family      = AF_INET;
  9189.  bindsock.sin_port        = 0;
  9190.  bindsock.sin_addr.s_addr = INADDR_ANY;
  9191.  
  9192.  sp->ns = socket(AF_INET, SOCK_STREAM, 0);
  9193.  if (sp->ns < 0) {
  9194.    REPORT_TCP_ERROR(gp->ggserver);
  9195.    ERR2("TCP/IP error: socket() failed to make socket for server %s.",
  9196.         gp->ggserver);
  9197.    return FALSE;
  9198.  }
  9199.  
  9200.  bindrc = Bind(sp->ns, &bindsock, sizeof(bindsock));
  9201.  if (bindrc < 0) {
  9202.    REPORT_TCP_ERROR(gp->ggserver);
  9203.    ERR2("TCP/IP error: bind() failed for socket %d", sp->ns);
  9204.    return FALSE;
  9205.  }
  9206.  
  9207.  ISPF("CONTROL DISPLAY LOCK");
  9208.  ISPF("DISPLAY PANEL(GGMLCONN)");
  9209.  
  9210.  if (gp->debug_file) {
  9211.    fprintf(gp->debug_file,
  9212.            "Client %s (%s) connecting to GOPHER server on %s (%s)\n",
  9213.            gp->client_hostname, gp->client_ip_addrstr,
  9214.            gp->server_hostname, gp->server_ip_addrstr);
  9215.  }
  9216.  
  9217.  connrc = Connect(sp->ns, &consock, sizeof(consock));
  9218.  if (connrc < 0) {
  9219.    REPORT_TCP_ERROR(gp->ggserver);
  9220.    ERR2("TCP/IP failure: connect() failed to connect to server %s.",
  9221.         gp->ggserver);
  9222.    return FALSE;
  9223.  }
  9224.  
  9225.  sp->connected_to_server = TRUE;
  9226.  sp->time_to_go_home     = FALSE;
  9227.  sp->connection_broken   = FALSE;
  9228.  sp->server_has_nothing  = FALSE;
  9229.  sp->dont_read           = FALSE;
  9230.  
  9231.  GGesrvr(gp,sp);   /* Clean up any stray responses from server. */
  9232.  
  9233.  return TRUE;
  9234.  
  9235. }
  9236.  
  9237. ./ ADD NAME=GGCSO
  9238.  
  9239.  /********************************************************************/
  9240.  /*                                                                  */
  9241.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  9242.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  9243.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  9244.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  9245.  /*                                                                  */
  9246.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  9247.  /* including the implied warranties of merchantability and fitness, */
  9248.  /* are expressly denied.                                            */
  9249.  /*                                                                  */
  9250.  /* Provided this copyright notice is included, this software may    */
  9251.  /* be freely distributed and not offered for sale.                  */
  9252.  /*                                                                  */
  9253.  /* Changes or modifications may be made and used only by the maker  */
  9254.  /* of same, and not further distributed.  Such modifications should */
  9255.  /* be mailed to the author for consideration for addition to the    */
  9256.  /* software and incorporation in subsequent releases.               */
  9257.  /*                                                                  */
  9258.  /********************************************************************/
  9259.  
  9260. #pragma  csect(code,  "GG@CSO")
  9261. #pragma  csect(static,"GG$CSO")
  9262. #include "gg.h"
  9263.  
  9264.  /********************************************************************
  9265.   *
  9266.   * The CSO code is due to:
  9267.   *
  9268.   * Lou Joseph     <cwmy5c@irishmvs.cc.nd.edu>
  9269.   * Rachna Agrawal <rachna@clemson.clemson.edu>
  9270.   *
  9271.   ********************************************************************/
  9272.  
  9273. /****** Gopher CSO interface. ************************************/
  9274.  
  9275. Bool
  9276. GGcso(gp,ip,as_file)
  9277. RGGCB   *gp;
  9278. RINFO   *ip;
  9279. GOHOW    as_file;
  9280. {
  9281.  RCONN  *sp;
  9282.  char   *lp;
  9283.  char   *rdel = ":";
  9284.  char   *rtoken;
  9285.  char   *rtok[5];
  9286.  char   *rstr[14];
  9287.  int     a;              /* field counter */
  9288.  int     b;              /* field counter */
  9289.  int     c;              /* field counter */
  9290.  int     d;              /* field counter */
  9291.  int     e_index_i;
  9292.  Bool    got_some;
  9293.  char    ggcsoq[14][256];
  9294.  char    e_index_c[10];
  9295.  char    sep[80] = "--------------------";
  9296.  
  9297.  sp = &gp->gopher_connection;
  9298.  
  9299.  strcpy(gp->ggserver,ip->host);     /* Specify server to connect to */
  9300.  
  9301.  /***** set up fields command to server ***** start ******************/
  9302.  
  9303.  strcpy(gp->gopher_command,"fields");
  9304.  
  9305.  /***** set up fields command to server ***** end   ******************/
  9306.  
  9307.  gp->ginfo = ip;
  9308.  if (!GGconn(gp,sp)) return FALSE;   /* Connect to CSO server */
  9309.  GOPHERSEND(gp,sp);                  /* Send socket command */
  9310.  GGclrtx(gp,ip);                     /* Clear text */
  9311.  
  9312.  for (d = 0; d < 4;  d++) rtok[d] = "";
  9313.  for (d = 0; d < 14; d++) rstr[d] = "";
  9314.  
  9315.  sp->receiving_text = TRUE;
  9316.  got_some = FALSE;
  9317.  a = 0;           /* controls that each field is output only once */
  9318.  b = 0;           /* counts the server line */
  9319.  c = 0;           /* counts number of tokens in each new line */
  9320.  d = 0;           /* counts that only some of the fields are saved */
  9321.  do {
  9322.    if (GGgsrvl(gp,sp,&lp,NOCR)) {              /* Get server line  */
  9323.      if (lp) {
  9324.        ++b;
  9325.        if (b == 2) {
  9326.           a = 1;
  9327.           b = 0;
  9328.        }      /* end if  (b == 2) */
  9329.        if (a == 1) {                              /* if new entry */
  9330.           c = 0;
  9331.           rtoken = strtok(lp,rdel);
  9332.           while (rtoken != NULL) {
  9333.               rtok[c] = rtoken;
  9334.               ++c;
  9335.               rtoken = strtok(NULL,rdel);
  9336.           }      /* end while  */
  9337.           a = 0;
  9338.           if (d < 14)  {
  9339.             GETMAIN(rstr[d],char,strlen(rtok[2]+1),"CSO field string");
  9340.             if (!rstr[d]) break;
  9341.             strcpy(rstr[d], rtok[2]);
  9342.             ++d;
  9343.           }
  9344.        }    /* end if new entry */
  9345.        got_some = TRUE;
  9346.        if (lp[0] != '-' && strncmp(lp,"200",3) >= 0) break;
  9347.      }        /* end if lp */
  9348.    }      /* end if GGgsrvl */
  9349.  } while (lp);                            /* until no more lines */
  9350.  
  9351.  if (!got_some) {
  9352.    WARN2("No data available from server %s.\n",gp->ggserver);
  9353.    return FALSE;
  9354.  }
  9355.  
  9356.  sp->receiving_text = FALSE;
  9357.  
  9358.  VPUT("FNAME1 ", rstr[0]  );
  9359.  VPUT("FNAME2 ", rstr[1]  );
  9360.  VPUT("FNAME3 ", rstr[2]  );
  9361.  VPUT("FNAME4 ", rstr[3]  );
  9362.  VPUT("FNAME5 ", rstr[4]  );
  9363.  VPUT("FNAME6 ", rstr[5]  );
  9364.  VPUT("FNAME7 ", rstr[6]  );
  9365.  VPUT("FNAME8 ", rstr[7]  );
  9366.  VPUT("FNAME9 ", rstr[8]  );
  9367.  VPUT("FNAME10 ",rstr[9]  );
  9368.  VPUT("FNAME11 ",rstr[10] );
  9369.  VPUT("FNAME12 ",rstr[11] );
  9370.  VPUT("FNAME13 ",rstr[12] );
  9371.  VPUT("FNAME14 ",rstr[13] );
  9372.  
  9373.  ISPF("VGET (FVALUE1) PROFILE");
  9374.  
  9375.  if (GGdispl(gp,"GGMCSO  ") > 0) return FALSE;
  9376.  
  9377.  VGET("FVALUE1 ", ggcsoq[0]  );
  9378.  VGET("FVALUE2 ", ggcsoq[1]  );
  9379.  VGET("FVALUE3 ", ggcsoq[2]  );
  9380.  VGET("FVALUE4 ", ggcsoq[3]  );
  9381.  VGET("FVALUE5 ", ggcsoq[4]  );
  9382.  VGET("FVALUE6 ", ggcsoq[5]  );
  9383.  VGET("FVALUE7 ", ggcsoq[6]  );
  9384.  VGET("FVALUE8 ", ggcsoq[7]  );
  9385.  VGET("FVALUE9 ", ggcsoq[8]  );
  9386.  VGET("FVALUE10 ",ggcsoq[9]  );
  9387.  VGET("FVALUE11 ",ggcsoq[10] );
  9388.  VGET("FVALUE12 ",ggcsoq[11] );
  9389.  VGET("FVALUE13 ",ggcsoq[12] );
  9390.  VGET("FVALUE14 ",ggcsoq[13] );
  9391.  
  9392.  /***** set up query command to server ****** start ******************/
  9393.  strcpy(gp->gopher_command,"query ");
  9394.  if (!*ip->path) {
  9395.     for (a = 0; a < 14; a++)
  9396.         if (strlen(ggcsoq[a]) != 0) {
  9397.            strcat(gp->gopher_command + 6, rstr[a]);
  9398.            strcat(gp->gopher_command, "=\"");
  9399.            strcat(gp->gopher_command, ggcsoq[a]);
  9400.            strcat(gp->gopher_command, "\" ");
  9401.         }
  9402.  }
  9403.  else {
  9404.     sprintf(gp->gopher_command + 6,"%s\t",ip->path);
  9405.     for (a = 0; a < 14; a++) {
  9406.         strcat(gp->gopher_command + 6, rstr[a]);
  9407.         strcat(gp->gopher_command," =\"");
  9408.         strcat(gp->gopher_command, ggcsoq[a]);
  9409.         strcat(gp->gopher_command, "\" ");
  9410.     }
  9411.  }
  9412.  strcat(gp->gopher_command," return all");
  9413.  
  9414.  /***** set up query command to server ******* end *******************/
  9415.  
  9416.  GOPHERSEND(gp,sp);               /* Send socket command */
  9417.  GGclrtx(gp,ip);                  /* Clear text */
  9418.  
  9419.  sp->receiving_text = TRUE;
  9420.  got_some = FALSE;
  9421.  e_index_i = 2;
  9422.  sprintf(e_index_c,":%u:",e_index_i);
  9423.  do {
  9424.    if (GGgsrvl(gp,sp,&lp,NOCR)) {           /* Get server line */
  9425.      if (lp) {
  9426.        if (strstr(lp,e_index_c) != NULL) {  /* if new entry */
  9427.          (void)GGouttx(gp,sep,ip,NO_VALUE); /* Output separator */
  9428.          ++e_index_i;                       /* Increment index  */
  9429.          sprintf(e_index_c,":%u:",e_index_i);
  9430.        }
  9431.        got_some = TRUE;
  9432.        (void)GGouttx(gp,lp,ip,NO_VALUE);    /* Output text line */
  9433.        if (lp[0] != '-' && strncmp(lp,"200",3) >= 0) break;
  9434.      }
  9435.    }
  9436.  } while (lp);                              /* until no more lines */
  9437.  
  9438.  if (!got_some) {
  9439.    WARN2("No data available from server %s.\n",gp->ggserver);
  9440.    return FALSE;
  9441.  }
  9442.  
  9443.  /* Send quit command        */
  9444.  
  9445.  sp->receiving_text = FALSE;
  9446.  strcpy(gp->gopher_command,"quit");
  9447.  GOPHERSEND(gp,sp);                   /* Send socket command */
  9448.  
  9449.  /* Read Bye message         */
  9450.  
  9451.  sp->receiving_text = TRUE;
  9452.  
  9453.  (void)GGgsrvl(gp,sp,&lp,NOCR);       /* Get server line */
  9454.  
  9455.  if (sp->connected_to_server) {
  9456.    (void)GGdisc(gp,sp);   /* Disconnect from CSO server */
  9457.  }
  9458.  
  9459.  GGvtx(gp,ip,as_file);    /* display text from CSO server */
  9460.  
  9461.  for (d = 0; d < 14; d++) {
  9462.    if (*rstr[d]) {
  9463.      FREEMAIN(rstr[d],"CSO field string");
  9464.    }
  9465.  }
  9466.  
  9467.  return TRUE;
  9468.  
  9469. }
  9470.  
  9471. ./ ADD NAME=GGDBM
  9472.  
  9473.  /********************************************************************/
  9474.  /*                                                                  */
  9475.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  9476.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  9477.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  9478.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  9479.  /*                                                                  */
  9480.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  9481.  /* including the implied warranties of merchantability and fitness, */
  9482.  /* are expressly denied.                                            */
  9483.  /*                                                                  */
  9484.  /* Provided this copyright notice is included, this software may    */
  9485.  /* be freely distributed and not offered for sale.                  */
  9486.  /*                                                                  */
  9487.  /* Changes or modifications may be made and used only by the maker  */
  9488.  /* of same, and not further distributed.  Such modifications should */
  9489.  /* be mailed to the author for consideration for addition to the    */
  9490.  /* software and incorporation in subsequent releases.               */
  9491.  /*                                                                  */
  9492.  /********************************************************************/
  9493.  
  9494. #pragma  csect(code,  "GG@DBM  ")
  9495. #pragma  csect(static,"GG$DBM  ")
  9496. #include "gg.h"
  9497.  
  9498. /****** Delete a bookmark from a bookmark data set. ******************/
  9499.  
  9500. Bool
  9501. GGdbm(gp,ip)
  9502. RGGCB   *gp;
  9503. RINFO   *ip;
  9504. {
  9505.  FILE   *xfp;
  9506.  char   *bufptr;
  9507.  char    test   [  6];
  9508.  char    dsname [129];
  9509.  char    buffer [RBUFSIZE];
  9510.  
  9511.  if (!*ip->bmds) {
  9512.    WARN1("Delete not possible.  This entry is not from a bookmark.");
  9513.    return FALSE;
  9514.  }
  9515.  
  9516.  VPUT("GGMDBMDS ",ip->bmds);
  9517.  VPUT("GGMDBMSU ",ip->desc);
  9518.  
  9519.  ISPF("ADDPOP");
  9520.  
  9521.  if (GGdispl(gp,"GGMPDBM ") > 0) {
  9522.    WARN1("Deletion cancelled, because you pressed END.");
  9523.    ISPF("REMPOP");
  9524.    return FALSE;
  9525.  }
  9526.  
  9527.  ISPF("REMPOP");
  9528.  
  9529.  sprintf(dsname,"'%s'",ip->bmds);
  9530.  xfp = fopen(dsname,"r");
  9531.  if (!xfp) {
  9532.    perror(dsname);
  9533.    ERR2("Cannot access bookmark data set %s.",dsname);
  9534.    return FALSE;
  9535.  }
  9536.  
  9537.  for (;;) {
  9538.    *buffer = '\0';
  9539.    fgets(buffer,sizeof(buffer),xfp);
  9540.    if (ferror(xfp)) {
  9541.      ERR2("Error reading bookmark data set %s.",dsname);
  9542.      break;
  9543.    }
  9544.    if (feof(xfp)) break;
  9545.    if ((bufptr=strchr(buffer,'\n'))) *bufptr = '\0';
  9546.    bufptr = skip_whitespace(buffer);
  9547.    CLEAR(test);
  9548.    memcpy(test,bufptr,5);
  9549.    uppercase_in_place(test);
  9550.  
  9551.    /*
  9552.    if      (EQUAL(test,"TYPE="))
  9553.    else if (EQUAL(test,"NAME="))
  9554.    else if (EQUAL(test,"PATH="))
  9555.    else if (EQUAL(test,"HOST="))
  9556.    else if (EQUAL(test,"PORT="))
  9557.    else if (EQUAL(test,"END"  ))
  9558.  
  9559.    */
  9560.  
  9561.  }
  9562.  
  9563.  (void)fclose(xfp);
  9564.  
  9565.  ERR1("Bookmark deletion is not yet supported, sorry.");
  9566.  return FALSE;
  9567.  
  9568. }
  9569.  
  9570. ./ ADD NAME=GGDFAIL
  9571.  
  9572.  /********************************************************************/
  9573.  /*                                                                  */
  9574.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  9575.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  9576.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  9577.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  9578.  /*                                                                  */
  9579.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  9580.  /* including the implied warranties of merchantability and fitness, */
  9581.  /* are expressly denied.                                            */
  9582.  /*                                                                  */
  9583.  /* Provided this copyright notice is included, this software may    */
  9584.  /* be freely distributed and not offered for sale.                  */
  9585.  /*                                                                  */
  9586.  /* Changes or modifications may be made and used only by the maker  */
  9587.  /* of same, and not further distributed.  Such modifications should */
  9588.  /* be mailed to the author for consideration for addition to the    */
  9589.  /* software and incorporation in subsequent releases.               */
  9590.  /*                                                                  */
  9591.  /********************************************************************/
  9592.  
  9593. #pragma  csect(code,  "GG@DFAIL")
  9594. #pragma  csect(static,"GG$DFAIL")
  9595. #include "gg.h"
  9596.  
  9597. /****** Retrieve allocation failure messages. ************************/
  9598.  
  9599. void
  9600. GGdfail(rc,p99)
  9601. int            rc;
  9602. __S99parms    *p99;
  9603. {
  9604.  int           zero = 0;
  9605.  unsigned int  dfid = 0x40320000;
  9606.  struct {
  9607.          short first_level_msg_len;
  9608.          short first_level_msg_offset;
  9609.          char  first_level_msg[251];
  9610.          short second_level_msg_len;
  9611.          short second_level_msg_offset;
  9612.          char  second_level_msg[251];
  9613.         }      dfbuffer;
  9614.  
  9615.  static int (*ikjeff18_pointer)() = NULL;
  9616.  
  9617. #ifndef FETCH
  9618.  extern int *ikjeff18();
  9619. #endif
  9620.  
  9621.  if (!ikjeff18_pointer) {
  9622. #ifdef FETCH
  9623.    ikjeff18_pointer = (int (*)())fetch("IKJEFF18");
  9624. #else
  9625.    ikjeff18_pointer = (int (*)())ikjeff18;
  9626. #endif
  9627.  }
  9628.  
  9629.  dfbuffer.first_level_msg_len = 4;
  9630.  dfbuffer.second_level_msg_len = 4;
  9631.  
  9632.  if (ikjeff18_pointer) {
  9633.    if ((*ikjeff18_pointer)(p99,&rc,&zero,&dfid,&zero,&dfbuffer)) {
  9634.      fprintf(stderr,"IKJEFF18 returned a nonzero return code\n");
  9635.    }
  9636.    if (dfbuffer.first_level_msg_len > 0) {
  9637.      fprintf(stderr,"%*.*s\n",
  9638.                     dfbuffer.first_level_msg_len-4,
  9639.                     dfbuffer.first_level_msg_len-4,
  9640.                     dfbuffer.first_level_msg);
  9641.    }
  9642.    if (dfbuffer.second_level_msg_len > 0) {
  9643.      fprintf(stderr,"%*.*s\n",
  9644.                     dfbuffer.second_level_msg_len-4,
  9645.                     dfbuffer.second_level_msg_len-4,
  9646.                     dfbuffer.second_level_msg);
  9647.    }
  9648.  }
  9649.  else {
  9650. #ifdef FETCH
  9651.    fprintf(stderr,"GGMVS: Cannot fetch IKJEFF18\n");
  9652. #else
  9653.    fprintf(stderr,"Cannot call IKJEFF18, not linked with GGMVS\n");
  9654. #endif
  9655.  }
  9656.  return;
  9657. }
  9658.  
  9659. ./ ADD NAME=GGDIR
  9660.  
  9661.  /********************************************************************/
  9662.  /*                                                                  */
  9663.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  9664.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  9665.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  9666.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  9667.  /*                                                                  */
  9668.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  9669.  /* including the implied warranties of merchantability and fitness, */
  9670.  /* are expressly denied.                                            */
  9671.  /*                                                                  */
  9672.  /* Provided this copyright notice is included, this software may    */
  9673.  /* be freely distributed and not offered for sale.                  */
  9674.  /*                                                                  */
  9675.  /* Changes or modifications may be made and used only by the maker  */
  9676.  /* of same, and not further distributed.  Such modifications should */
  9677.  /* be mailed to the author for consideration for addition to the    */
  9678.  /* software and incorporation in subsequent releases.               */
  9679.  /*                                                                  */
  9680.  /********************************************************************/
  9681.  
  9682. #pragma  csect(code,  "GG@DIR  ")
  9683. #pragma  csect(static,"GG$DIR  ")
  9684. #include "gg.h"
  9685.  
  9686. /*********************************************************************/
  9687.  
  9688. static Bool
  9689. valid_code(c)
  9690. char       c;
  9691. {
  9692.  
  9693.  switch (c) {
  9694.    case GOPHER_FILE:
  9695.    case GOPHER_DIRECTORY:
  9696.    case GOPHER_TELNET:
  9697.    case GOPHER_TN3270:
  9698.    case GOPHER_WAIS:
  9699.    case GOPHER_WHOIS:
  9700.    case GOPHER_CSO:
  9701.    case GOPHER_ERROR:
  9702.    case GOPHER_BOOKMANAGER:
  9703.    case GOPHER_MAC_BINHEX:
  9704.    case GOPHER_DOS_BINARCH:
  9705.    case GOPHER_BINARY:
  9706.    case GOPHER_COMMENT:
  9707.                            return TRUE;
  9708.    default:                return FALSE;
  9709.   }
  9710.  
  9711. }
  9712.  
  9713. /*********************************************************************/
  9714.  
  9715. static Bool
  9716. process_s_selection(gp,ip)
  9717. RGGCB              *gp;
  9718. RINFO              *ip;
  9719. {
  9720.  
  9721.  GGgofor(gp,ip,AS_NORMAL);
  9722.  return TRUE;
  9723. }
  9724.  
  9725. /*********************************************************************/
  9726.  
  9727. static Bool
  9728. process_i_selection(gp,ip)
  9729. RGGCB              *gp;
  9730. RINFO              *ip;
  9731. {
  9732.  
  9733.  if (!GGinfo(gp,ip)) return FALSE;
  9734.  GGvtx(gp,NULL,AS_FILE);
  9735.  return TRUE;
  9736. }
  9737.  
  9738. /*********************************************************************/
  9739.  
  9740. static Bool
  9741. process_b_selection(gp,ip)
  9742. RGGCB              *gp;
  9743. RINFO              *ip;
  9744. {
  9745.  
  9746.  if (!GGinfo(gp,ip)) return FALSE;
  9747.  gp->extract_file = NULL;
  9748.  GGxtx(gp,ip,BOOKMARK_IT);
  9749.  return TRUE;
  9750. }
  9751.  
  9752. /*********************************************************************/
  9753.  
  9754. static Bool
  9755. process_d_selection(gp,ip)
  9756. RGGCB              *gp;
  9757. RINFO              *ip;
  9758. {
  9759.  
  9760.  return GGdbm(gp,ip);
  9761. }
  9762.  
  9763. /*********************************************************************/
  9764.  
  9765. static Bool
  9766. process_e_selection(gp,ip)
  9767. RGGCB              *gp;
  9768. RINFO              *ip;
  9769. {
  9770.  
  9771.  if (!ip->thdr.first_text_line) {
  9772.    GGgofor(gp,ip,AS_NOTHING);
  9773.  }
  9774.  if (!ip->thdr.first_text_line) return FALSE;
  9775.  gp->extract_file = NULL;
  9776.  GGxtx(gp,ip,EXTRACT_IT);
  9777.  return TRUE;
  9778. }
  9779.  
  9780. /*********************************************************************/
  9781.  
  9782. static Bool
  9783. process_p_selection(gp,ip)
  9784. RGGCB              *gp;
  9785. RINFO              *ip;
  9786. {
  9787.  
  9788.  if (!ip->thdr.first_text_line) {
  9789.    GGgofor(gp,ip,AS_NOTHING);
  9790.  }
  9791.  if (!ip->thdr.first_text_line) return FALSE;
  9792.  gp->extract_file = NULL;
  9793.  GGxtx(gp,ip,PRINT_IT);
  9794.  return TRUE;
  9795. }
  9796.  
  9797. /*********************************************************************/
  9798.  
  9799. static Bool
  9800. process_q_selection(gp,ip)
  9801. RGGCB              *gp;
  9802. RINFO              *ip;
  9803. {
  9804.  
  9805.  GGgofor(gp,ip,AS_FILE);
  9806.  return TRUE;
  9807. }
  9808.  
  9809. /*********************************************************************/
  9810.  
  9811. static Bool
  9812. display_dynamic_area(gp,ip,infoarray,entrycount)
  9813. RGGCB               *gp;
  9814. RINFO               *ip;
  9815. GOPHERINFO          *infoarray;
  9816. int                  entrycount;
  9817. {
  9818.  GOPHERINFO         *iap;
  9819.  int                 depth;
  9820.  int                 ggglvl;
  9821.  int                 dynsize;
  9822.  int                 topitem;
  9823.  int                 bottomitem;
  9824.  int                 last_item_selected;
  9825.  int                 dti;
  9826.  int                 gii;
  9827.  int                 prc;
  9828.  int                 l;
  9829.  int                 command_index;
  9830.  int                 zscrolln;
  9831.  int                 leftcol;
  9832.  int                 maxcol;
  9833.  int                 menucursor;
  9834.  Bool                selok;
  9835.  Bool                cmdok;
  9836.  Bool                is_max;
  9837.  Bool                is_csr;
  9838.  char               *gggdyna;
  9839.  char               *rowp;
  9840.  char               *cp;
  9841.  char                gggcmd     [72];
  9842.  char                zverb       [9];
  9843.  char                zscrolla    [9];
  9844.  char                command    [COMMANDSIZE];
  9845.  char                ggghead    [81];
  9846.  char                rowmessage [81];
  9847.  
  9848.  /* Get depth of dynamic area (number of rows to display on screen) */
  9849.  
  9850.  ISPF("PQUERY PANEL(GGMDIR) AREANAME(GGGDYNA) DEPTH(GGGDEPTH)");
  9851.  if (gp->ispfrc != 0) return FALSE;
  9852.  depth = IGET("GGGDEPTH ");
  9853.  
  9854.  /* Get storage for ISPF dynamic area variable to be constructed. */
  9855.  
  9856.  dynsize = 80*depth;
  9857.  GETMAIN(gggdyna, char, dynsize+1, "GGGDYNA buffer");
  9858.  if (!gggdyna) return FALSE;
  9859.  
  9860.  /* Loop displaying the panel until END pressed. */
  9861.  
  9862.  last_item_selected = -1;
  9863.  strcpy(gggcmd,"");
  9864.  topitem    = 0;
  9865.  leftcol    = 0;
  9866.  menucursor = 0;
  9867.  prc        = 0;
  9868.  maxcol     = 0;
  9869.  for (gii = 0; gii < entrycount; gii++) {
  9870.    l = strlen(infoarray[gii].desc);
  9871.    if (maxcol < l) maxcol = l;
  9872.  }
  9873.  
  9874.  while (prc == 0) {
  9875.  
  9876.  /* Fill in the dynamic area with rows, one for each gopher item. */
  9877.  
  9878.    memset(gggdyna,' ',dynsize);
  9879.    menucursor = 0;
  9880.  
  9881.    for (dti = 0,       gii = topitem,     rowp = gggdyna;
  9882.         dti < depth && gii < entrycount;
  9883.         dti++,         gii++,             rowp += 80) {
  9884.      iap = &infoarray[gii];
  9885.      if (gp->autocursor && gii == last_item_selected) {
  9886.        menucursor = rowp + 2 - gggdyna;
  9887.      }
  9888.      if (iap->type == GOPHER_COMMENT
  9889.       || iap->type == GOPHER_ERROR)
  9890.        rowp[ 0] = DATAOUT_HIGH;          /* selection code protected */
  9891.      else
  9892.        rowp[ 0] = DATAIN_HIGH;           /* selection code attribute */
  9893.      rowp[ 1] = ' ';                     /* selection code field     */
  9894.      rowp[ 2] = DATAOUT_GREEN;           /* icon attribute           */
  9895.      memcpy(&rowp[ 3],GGtype(iap->type),9);
  9896.      rowp[12] = DATAOUT_HIGH;            /* description attribute    */
  9897.      l = strlen(iap->desc) - leftcol;
  9898.      if (l > 0) memcpy(&rowp[13], iap->desc + leftcol, l>67 ? 67 : l);
  9899.    }
  9900.  
  9901.    if (rowp < gggdyna + dynsize) {
  9902.      rowp[0] = DATAOUT_HIGH;
  9903.      memset(&rowp[1], '-',79);
  9904.    }
  9905.  
  9906.    bottomitem = gii - 1;
  9907.    if (topitem > bottomitem) strcpy(rowmessage,"");
  9908.    else sprintf(rowmessage, " %d-%d of %d",
  9909.                             topitem + 1, bottomitem + 1, entrycount);
  9910.    memset(ggghead,' ',79);
  9911.    ggghead[79] = '\0';
  9912.    strcpy(ggghead,"GOPHER - ");
  9913.    strncpy(ggghead+9,ip->desc,70);
  9914.    *strchr(ggghead,'\0') = ' ';
  9915.    memcpy(ggghead+79-strlen(rowmessage),rowmessage,strlen(rowmessage));
  9916.  
  9917.    if (menucursor > 0) {
  9918.      IPUT("GGGCSR ", menucursor);
  9919.    }
  9920.    else VPUT("GGGCSR ", "0");
  9921.    VPUTS("GGGHEAD ",ggghead,79);
  9922.    VPUTS("GGGDYNA ",gggdyna, dynsize);
  9923.    VPUT ("GGGCMD " ,gggcmd);
  9924.  
  9925.    if ((prc=GGdispl(gp,"GGMDIR  ")) > 8) break;
  9926.  
  9927.    VGETS("GGGDYNA " , gggdyna, dynsize);
  9928.    VGET ("ZVERB "   , zverb);
  9929.    VGET ("ZSCROLLA ", zscrolla);
  9930.    zscrolln = IGET("ZSCROLLN ");
  9931.    ggglvl   = IGET("GGGLVL ");
  9932.    last_item_selected = -1;
  9933.  
  9934.    /* Process selections. */
  9935.  
  9936.    for (gii = topitem,     rowp = gggdyna;
  9937.         gii <= bottomitem;
  9938.         gii++,             rowp += 80) {
  9939.      iap = &infoarray[gii];
  9940.      switch (toupper(rowp[1])) {
  9941.        case ' ':  continue;
  9942.        case 'S':  selok = process_s_selection(gp,iap); break;
  9943.        case 'E':  selok = process_e_selection(gp,iap); break;
  9944.        case 'P':  selok = process_p_selection(gp,iap); break;
  9945.        case 'Q':  selok = process_q_selection(gp,iap); break;
  9946.        case 'I':  selok = process_i_selection(gp,iap); break;
  9947.        case 'B':  selok = process_b_selection(gp,iap); break;
  9948.    /*  case 'D':  selok = process_d_selection(gp,iap); break; */
  9949.        default:
  9950.         ERR1("Unknown selection code.  Type one of the listed codes.");
  9951.                   selok = FALSE;                       break;
  9952.      }
  9953.      if (selok) last_item_selected = gii;
  9954.      if (gp->quit) break;
  9955.    }
  9956.  
  9957.    /* Process command if any. */
  9958.  
  9959.    VGET("GGGCMD ",gggcmd);
  9960.    if (*gggcmd) {
  9961.      cmdok = TRUE;
  9962.      memset(command,' ',COMMANDSIZE);
  9963.      command_index = 0;
  9964.      for (cp = gggcmd; *cp && !isspace(*cp); cp++) {
  9965.        if (cp >= gggcmd+COMMANDSIZE) {
  9966.          ERR1(
  9967.  "Invalid command.  Try \"OPTIONS\", \"MENU bookmarkname\", \"QUIT\"");
  9968.          cmdok = FALSE;
  9969.        }
  9970.        command[command_index++] = toupper(*cp);
  9971.      }
  9972.      while (*cp && isspace(*cp)) cp++;
  9973.      if      (!memcmp(command,"QUIT    ",8)) gp->quit = TRUE;
  9974.      else if (!memcmp(command,"MENU    ",8)) GGmenu(gp,cp);
  9975.      else if (!memcmp(command,"OPT     ",8)
  9976.            || !memcmp(command,"OPTION  ",8)
  9977.            || !memcmp(command,"OPTIONS ",8)) GGdsopt(gp,cp);
  9978.      else if (!memcmp(command,"TEST    ",8)) {
  9979.                                               gp->test_mode = TRUE;
  9980.                                               __ctest(NULL);
  9981.                                              }
  9982.      else {
  9983.        ERR1(
  9984.  "Unknown command.  Try \"OPTIONS\", \"MENU bookmarkname\", \"QUIT\"");
  9985.        cmdok = FALSE;
  9986.      }
  9987.      if (cmdok) strcpy(gggcmd,"");
  9988.    }
  9989.  
  9990.    if (gp->quit) break;
  9991.  
  9992.    if (last_item_selected >= 0 && gp->autoscroll) {
  9993.      topitem = last_item_selected;
  9994.    }
  9995.  
  9996.    /* Process scroll request if any. */
  9997.  
  9998.    is_max = EQUAL(zscrolla,"MAX");
  9999.    is_csr = zscrolla[0] == 'C';
  10000.    if      (EQUAL(zverb,"DOWN")) {
  10001.      if (is_max) topitem = entrycount - ggglvl;
  10002.      else        topitem += zscrolln;
  10003.    }
  10004.    else if (EQUAL(zverb,"UP")) {
  10005.      if (is_max) topitem = 0;
  10006.      else        topitem -= zscrolln;
  10007.    }
  10008.    else if (EQUAL(zverb,"LEFT")) {
  10009.      if (is_max) leftcol = 0;
  10010.      else        leftcol -= zscrolln;
  10011.    }
  10012.    else if (EQUAL(zverb,"RIGHT")) {
  10013.      if (is_csr) zscrolln -= 13;
  10014.      if (is_max) leftcol = maxcol - 67;
  10015.      else        leftcol += zscrolln;
  10016.    }
  10017.    else if (EQUAL(zverb,"RETURN")) {
  10018.      gp->quit = TRUE;
  10019.      break;
  10020.    }
  10021.    if (topitem < 0)          topitem = 0;
  10022.    if (topitem > entrycount) topitem = entrycount;
  10023.    if (leftcol < 0)          leftcol = 0;
  10024.    if (leftcol > maxcol)     leftcol = maxcol;
  10025.  
  10026.  } /* end while prc == 0 */
  10027.  
  10028.  return;
  10029.  
  10030. }
  10031.  
  10032. /****** Gopher a directory. ******************************************/
  10033.  
  10034. Bool
  10035. GGdir(gp,ip,how)
  10036. RGGCB      *gp;
  10037. RINFO      *ip;
  10038. GOHOW       how;
  10039. {
  10040.  int            entrycount;
  10041.  int            i;
  10042.  int            copysize;
  10043.  char           typechar;
  10044.  char           savechar;
  10045.  char          *p;
  10046.  char          *q;
  10047.  char          *r;
  10048.  TEXTLINE      *tp;
  10049.  GOPHERINFO    *infoarray;
  10050.  GOPHERINFO    *iap;
  10051.  char           temp [16];
  10052.  
  10053.  switch (how) {
  10054.    case AS_FILE:    GGvtx(gp,ip,AS_FILE);  /* display text as is */
  10055.                     return TRUE;
  10056.    case AS_NOTHING: return TRUE;           /* prepare for extract */
  10057.    case AS_NORMAL:
  10058.    default:         break;
  10059.  }
  10060.  
  10061.  /* The text chain contains the data from the server, which should be
  10062.   * in the following format:
  10063.   *
  10064.   * nDescription^Path^foo^bar
  10065.   *
  10066.   * where the "n" in the beginning is a digit and ^ means a tab char.
  10067.   *
  10068.   * Logic:
  10069.   *
  10070.   * Build an array of gopherinfo structs from the text records.
  10071.   * Display them as an ISPF dynamic area pseudotable.
  10072.   * Let the user select them, and run GGgofor on each one
  10073.   * with a struct gopherinfo built from the contents.
  10074.   *
  10075.   */
  10076.  
  10077.  /* Determine size of array of gopherinfo structs.  This is equal to
  10078.   * the number of text records with a valid code in the first byte.
  10079.   */
  10080.  
  10081.  entrycount = 0;
  10082.  for (tp = ip->thdr.first_text_line; tp; tp = tp->next) {
  10083.    if (valid_code(tp->text[0])) entrycount++;
  10084.  }
  10085.  
  10086.  if (entrycount == 0) {
  10087.    ERR1("There seems to be no information in this directory.\n");
  10088.    return FALSE;
  10089.  }
  10090.  
  10091.  /* Allocate an array of structs to hold the stuff. */
  10092.  
  10093.  GETMAIN(infoarray, struct gopherinfo, entrycount,"gopherinfo array");
  10094.  
  10095.  if (!infoarray) {
  10096.    ERR2("Not enough memory for %d gopher directory entries\n",
  10097.         entrycount);
  10098.    return FALSE;
  10099.  }
  10100.  
  10101.  /* Build the array entries. */
  10102.  
  10103.  iap = infoarray;
  10104.  for (tp = ip->thdr.first_text_line; tp; tp = tp->next) {
  10105.    typechar = tp->text[0];
  10106.    if (valid_code(typechar)) {
  10107.      r = &tp->text[tp->text_length];
  10108.      savechar = *r;
  10109.      *r = '\t';
  10110.      memset(iap,0,sizeof(struct gopherinfo));
  10111.      iap->port = GOPHER_PORT_NUMBER;
  10112.      iap->type = (GOPHERTYPE)typechar;
  10113.      p = &tp->text[1];
  10114.      q = strchr(p,'\t');
  10115.      copysize = sizeof(iap->desc)-1;
  10116.      if (copysize > q-p) copysize = q-p;
  10117.      memcpy(iap->desc,p,copysize);
  10118.      if (q < r) {
  10119.        p = q+1;
  10120.        q = strchr(p,'\t');
  10121.        copysize = sizeof(iap->path)-1;
  10122.        if (copysize > q-p) copysize = q-p;
  10123.        memcpy(iap->path,p,copysize);
  10124.        if (q < r) {
  10125.          p = q+1;
  10126.          q = strchr(p,'\t');
  10127.          copysize = sizeof(iap->host)-1;
  10128.          if (copysize > q-p) copysize = q-p;
  10129.          memcpy(iap->host,p,copysize);
  10130.          if (q < r) {
  10131.            p = q+1;
  10132.            q = strchr(p,'\t');
  10133.            memset(temp,0,sizeof(temp));
  10134.            copysize = sizeof(temp)-1;
  10135.            if (copysize > q-p) copysize = q-p;
  10136.            memcpy(temp,p,copysize);
  10137.            iap->port = atoi(temp);
  10138.          }
  10139.        }
  10140.      }
  10141.      strcpy(iap->bmds,gp->current_bookmark_ds);
  10142.      *r = savechar;
  10143.      iap++;
  10144.    }
  10145.  }
  10146.  
  10147.  if (gp->debug_mode) {
  10148.    for (iap = infoarray, i = entrycount; i > 0; iap++, i--) {
  10149.      fprintf(gp->debug_file,"GGdir: type = %d\n",iap->type);
  10150.      fprintf(gp->debug_file,"GGdir: port = %d\n",iap->port);
  10151.      fprintf(gp->debug_file,"GGdir: path = %s\n",iap->path);
  10152.      fprintf(gp->debug_file,"GGdir: host = %s\n",iap->host);
  10153.      fprintf(gp->debug_file,"GGdir: desc = %s\n",iap->desc);
  10154.      fprintf(gp->debug_file,"GGdir: bmds = %s\n",iap->bmds);
  10155.      fprintf(gp->debug_file,"\n");
  10156.    }
  10157.  }
  10158.  
  10159.  display_dynamic_area(gp,ip,infoarray,entrycount);
  10160.  
  10161.  FREEMAIN(infoarray,"gopherinfo array");
  10162.  
  10163.  return TRUE;
  10164. }
  10165.  
  10166. ./ ADD NAME=GGDISC
  10167.  
  10168.  /********************************************************************/
  10169.  /*                                                                  */
  10170.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  10171.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  10172.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  10173.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  10174.  /*                                                                  */
  10175.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  10176.  /* including the implied warranties of merchantability and fitness, */
  10177.  /* are expressly denied.                                            */
  10178.  /*                                                                  */
  10179.  /* Provided this copyright notice is included, this software may    */
  10180.  /* be freely distributed and not offered for sale.                  */
  10181.  /*                                                                  */
  10182.  /* Changes or modifications may be made and used only by the maker  */
  10183.  /* of same, and not further distributed.  Such modifications should */
  10184.  /* be mailed to the author for consideration for addition to the    */
  10185.  /* software and incorporation in subsequent releases.               */
  10186.  /*                                                                  */
  10187.  /********************************************************************/
  10188.  
  10189. #pragma  csect(code,  "GG@DISC ")
  10190. #pragma  csect(static,"GG$DISC ")
  10191. #include "gg.h"
  10192.  
  10193. /****** Disconnect from gopher server. ********************************/
  10194.  
  10195. void
  10196. GGdisc(gp,sp)
  10197. RGGCB *gp;
  10198. RCONN *sp;
  10199. {
  10200.  RECV *R;
  10201.  
  10202.  /* If local mode, close temporary file and return. */
  10203.  
  10204.  if ((R=gp->recvp)) {
  10205.    if (R->outfp) {
  10206.      if (fclose(R->outfp) < 0) {
  10207.        CRIT1("Error closing local mode temporary file");
  10208.      }
  10209.      R->outfp = NULL;
  10210.    }
  10211.    sp->connected_to_server = FALSE;
  10212.    FREEMAIN(gp->recvp,"local mode recv struct");
  10213.    gp->recvp = NULL;
  10214.    return;
  10215.  }
  10216.  
  10217.  sp->closing_connection = TRUE;
  10218.  
  10219.  if (sp->connection_broken) {
  10220.    if (gp->debug_file) {
  10221.      fprintf(gp->debug_file,
  10222.   "Client %s (%s) connection with gopher server on %s (%s) was lost\n",
  10223.           gp->client_hostname,
  10224.           gp->client_ip_addrstr,
  10225.           gp->server_hostname,
  10226.           gp->server_ip_addrstr);
  10227.    }
  10228.    sp->connected_to_server = FALSE;
  10229.  }
  10230.  else {
  10231.  
  10232.    if (gp->debug_file) {
  10233.      fprintf(gp->debug_file,
  10234.       "Client %s (%s) disconnecting from gopher server on %s (%s)\n",
  10235.           gp->client_hostname,
  10236.           gp->client_ip_addrstr,
  10237.           gp->server_hostname,
  10238.           gp->server_ip_addrstr);
  10239.    }
  10240.  
  10241.    VPUT("GGSOLDER ",gp->server_hostname);
  10242.    VPUT("GGSOLDIP ",gp->server_ip_addrstr);
  10243.    ISPF("CONTROL DISPLAY LOCK");
  10244.    ISPF("DISPLAY PANEL(GGMLDISC)");
  10245.  
  10246.    GGesrvr(gp,sp);                   /* End server read */
  10247.  
  10248.    sp->connected_to_server = FALSE;
  10249.  
  10250.    if (close(sp->ns) < 0) {
  10251.      ERR2("TCP/IP error: close() failed to disconnect from server %s.",
  10252.           gp->ggserver);
  10253.    }
  10254.  }
  10255.  
  10256.  return;
  10257. }
  10258.  
  10259. ./ ADD NAME=GGDISPL
  10260.  
  10261.  /********************************************************************/
  10262.  /*                                                                  */
  10263.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  10264.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  10265.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  10266.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  10267.  /*                                                                  */
  10268.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  10269.  /* including the implied warranties of merchantability and fitness, */
  10270.  /* are expressly denied.                                            */
  10271.  /*                                                                  */
  10272.  /* Provided this copyright notice is included, this software may    */
  10273.  /* be freely distributed and not offered for sale.                  */
  10274.  /*                                                                  */
  10275.  /* Changes or modifications may be made and used only by the maker  */
  10276.  /* of same, and not further distributed.  Such modifications should */
  10277.  /* be mailed to the author for consideration for addition to the    */
  10278.  /* software and incorporation in subsequent releases.               */
  10279.  /*                                                                  */
  10280.  /********************************************************************/
  10281.  
  10282. #pragma  csect(code,  "GG@DISPL")
  10283. #pragma  csect(static,"GG$DISPL")
  10284. #include "gg.h"
  10285.  
  10286. #ifdef FETCH
  10287. #define VL_BIT(X) ((unsigned int)(X) | 0x80000000)
  10288. #else
  10289. #define VL_BIT(X) (X)
  10290. #endif
  10291.  
  10292. /****** Display ISPF panel. ******************************************/
  10293.  
  10294. int
  10295. GGdispl(gp,pan8)
  10296. RGGCB  *gp;
  10297. char   *pan8;
  10298. {
  10299.  
  10300.  if (gp->setmsg)
  10301.       gp->ispfrc = ISPLINK("DISPLAY ", pan8, VL_BIT("ISRZ002 "));
  10302.  else gp->ispfrc = ISPLINK("DISPLAY ", VL_BIT(pan8));
  10303.  
  10304.  if (gp->ispfrc > 8) GGierr(gp);   /* display ISPF error */
  10305.  gp->setmsg = FALSE;
  10306.  return gp->ispfrc;
  10307. }
  10308.  
  10309. ./ ADD NAME=GGDSOPT
  10310.  
  10311.  /********************************************************************/
  10312.  /*                                                                  */
  10313.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  10314.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  10315.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  10316.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  10317.  /*                                                                  */
  10318.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  10319.  /* including the implied warranties of merchantability and fitness, */
  10320.  /* are expressly denied.                                            */
  10321.  /*                                                                  */
  10322.  /* Provided this copyright notice is included, this software may    */
  10323.  /* be freely distributed and not offered for sale.                  */
  10324.  /*                                                                  */
  10325.  /* Changes or modifications may be made and used only by the maker  */
  10326.  /* of same, and not further distributed.  Such modifications should */
  10327.  /* be mailed to the author for consideration for addition to the    */
  10328.  /* software and incorporation in subsequent releases.               */
  10329.  /*                                                                  */
  10330.  /********************************************************************/
  10331.  
  10332. #pragma  csect(code,  "GG@DSOPT")
  10333. #pragma  csect(static,"GG$DSOPT")
  10334. #include "gg.h"
  10335.  
  10336. /****** Set options. *************************************************/
  10337.  
  10338. static void
  10339. setoptions(gp,panelname,which)
  10340. RGGCB     *gp;
  10341. char      *panelname;
  10342. OPTION     which;
  10343. {
  10344.  
  10345.  while (GGdispl(gp,panelname) == 0) {
  10346.    GGsopt(gp,which);               /* Actually set options */
  10347.  }
  10348.  
  10349.  return;
  10350. }
  10351.  
  10352. /****** Option ... set GOPHER default processing options. ***********/
  10353.  
  10354. void
  10355. GGdsopt(gp,option)
  10356. RGGCB  *gp;
  10357. char   *option;
  10358. {
  10359.  Bool   force_choice = FALSE;
  10360.  char   ggchoice [9];
  10361.  
  10362.  static char *message = "Invalid choice;\
  10363. Move the cursor to a selection (or type S next to it) and press ENTER.";
  10364.  
  10365.  for (;;) {
  10366.    if (!force_choice && option && *option) {
  10367.      strncpy(ggchoice,option,sizeof(ggchoice)-1);
  10368.    }
  10369.    else {
  10370.      ISPF("ADDPOP");
  10371.      if (GGdispl(gp,"GGMPOPT ") > 0) {
  10372.        ISPF("REMPOP");
  10373.        break;
  10374.      }
  10375.      VGET("GGCHOICE ",ggchoice);
  10376.      if (*ggchoice == '?') ERR1(message);
  10377.      ISPF("REMPOP");
  10378.    }
  10379.    if      (EQUAL(ggchoice,"1")) setoptions(gp,"GGMOPT1 ",OPTION_VIEW);
  10380.    else if (EQUAL(ggchoice,"2")) setoptions(gp,"GGMOPT2 ",OPTION_OTHER);
  10381.    else {
  10382.      ERR1(message);
  10383.      force_choice = TRUE;
  10384.      continue;
  10385.    }
  10386.    break;
  10387.  }
  10388.  
  10389.  return;
  10390.  
  10391. }
  10392.  
  10393. ./ ADD NAME=GGDUMP
  10394.  
  10395.  /********************************************************************/
  10396.  /*                                                                  */
  10397.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  10398.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  10399.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  10400.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  10401.  /*                                                                  */
  10402.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  10403.  /* including the implied warranties of merchantability and fitness, */
  10404.  /* are expressly denied.                                            */
  10405.  /*                                                                  */
  10406.  /* Provided this copyright notice is included, this software may    */
  10407.  /* be freely distributed and not offered for sale.                  */
  10408.  /*                                                                  */
  10409.  /* Changes or modifications may be made and used only by the maker  */
  10410.  /* of same, and not further distributed.  Such modifications should */
  10411.  /* be mailed to the author for consideration for addition to the    */
  10412.  /* software and incorporation in subsequent releases.               */
  10413.  /*                                                                  */
  10414.  /********************************************************************/
  10415.  
  10416. #pragma  csect(code,  "GG@DUMP ")
  10417. #pragma  csect(static,"GG$DUMP ")
  10418. #include "gg.h"
  10419.  
  10420. /****** Dump some data. **********************************************/
  10421.  
  10422. void
  10423. GGdump(GGCB *gp,
  10424.        char *label,
  10425.        char *p,
  10426.        int   r)
  10427. {
  10428.  int         i;
  10429.  
  10430.  if (!gp->debug_file) return;
  10431.  switch (r) {
  10432.    case -2: fprintf(gp->debug_file,"%s:  %d\n",label,(int)p); return;
  10433.    case -1: r = strlen(p); break;
  10434.  }
  10435.  fprintf(gp->debug_file,"%s:   (%d characters)\n",label,r);
  10436.  fprintf(gp->debug_file, "---------------------------------------"
  10437.                          "--------------------------------------\n");
  10438.  for (i=0;i<r;i++) {
  10439.    if (isprint(p[i])) fprintf(gp->debug_file,"%c",p[i]);
  10440.    else               fprintf(gp->debug_file,"<0x%2.2x>",p[i]);
  10441.  }
  10442.  fprintf(gp->debug_file,"\n");
  10443.  fprintf(gp->debug_file, "---------------------------------------"
  10444.                          "--------------------------------------\n");
  10445.  return;
  10446.  
  10447. }
  10448.  
  10449. ./ ADD NAME=GGESRVR
  10450.  
  10451.  /********************************************************************/
  10452.  /*                                                                  */
  10453.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  10454.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  10455.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  10456.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  10457.  /*                                                                  */
  10458.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  10459.  /* including the implied warranties of merchantability and fitness, */
  10460.  /* are expressly denied.                                            */
  10461.  /*                                                                  */
  10462.  /* Provided this copyright notice is included, this software may    */
  10463.  /* be freely distributed and not offered for sale.                  */
  10464.  /*                                                                  */
  10465.  /* Changes or modifications may be made and used only by the maker  */
  10466.  /* of same, and not further distributed.  Such modifications should */
  10467.  /* be mailed to the author for consideration for addition to the    */
  10468.  /* software and incorporation in subsequent releases.               */
  10469.  /*                                                                  */
  10470.  /********************************************************************/
  10471.  
  10472. #pragma  csect(code,  "GG@ESRVR")
  10473. #pragma  csect(static,"GG$ESRVR")
  10474. #include "gg.h"
  10475.  
  10476. /****** End server read. *********************************************/
  10477.  
  10478. void
  10479. GGesrvr(gp,sp)
  10480. RGGCB  *gp;
  10481. RCONN  *sp;
  10482. {
  10483.  char  *lp;
  10484.  Bool   found_more_server_data = FALSE;
  10485.  
  10486.  if (!gp) return;
  10487.  GGclrtx(gp,NULL);                     /* Clear text */
  10488.  if (gp->recvp) return;                /* Skip if non-socket */
  10489.  
  10490.  while (GGgsrvl(gp,sp,&lp,NOCR)) {     /* Get server line */
  10491.    if (!lp) break;
  10492.    found_more_server_data = TRUE;
  10493.    (void)GGouttx(gp,lp,NULL,NO_VALUE); /* Output text line */
  10494.  }
  10495.  
  10496.  if (found_more_server_data) {
  10497.    ERR1("More data was returned by the GOPHER server than expected.");
  10498.    GGvtx(gp,NULL,TRUE);                /* View text */
  10499.  }
  10500.  
  10501.  return;
  10502. }
  10503.  
  10504. ./ ADD NAME=GGFREEM
  10505.  
  10506.  /********************************************************************/
  10507.  /*                                                                  */
  10508.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  10509.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  10510.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  10511.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  10512.  /*                                                                  */
  10513.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  10514.  /* including the implied warranties of merchantability and fitness, */
  10515.  /* are expressly denied.                                            */
  10516.  /*                                                                  */
  10517.  /* Provided this copyright notice is included, this software may    */
  10518.  /* be freely distributed and not offered for sale.                  */
  10519.  /*                                                                  */
  10520.  /* Changes or modifications may be made and used only by the maker  */
  10521.  /* of same, and not further distributed.  Such modifications should */
  10522.  /* be mailed to the author for consideration for addition to the    */
  10523.  /* software and incorporation in subsequent releases.               */
  10524.  /*                                                                  */
  10525.  /********************************************************************/
  10526.  
  10527. #pragma  csect(code,  "GG@FREEM")
  10528. #pragma  csect(static,"GG$FREEM")
  10529. #include "gg.h"
  10530.  
  10531. /****** Free memory. *************************************************/
  10532.  
  10533. void
  10534. GGfreem(gp,stuff,whatfor)
  10535. RGGCB  *gp;
  10536. char   *stuff;
  10537. char   *whatfor;
  10538. {
  10539.  
  10540.  free(stuff);
  10541.  if (gp && gp->debug_file) {
  10542.    fprintf(gp->debug_file,"GGfreem: freed memory for %s\n", whatfor);
  10543.  }
  10544.  return;
  10545.  
  10546. }
  10547.  
  10548. ./ ADD NAME=GGFTP
  10549.  
  10550.  /********************************************************************/
  10551.  /*                                                                  */
  10552.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  10553.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  10554.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  10555.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  10556.  /*                                                                  */
  10557.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  10558.  /* including the implied warranties of merchantability and fitness, */
  10559.  /* are expressly denied.                                            */
  10560.  /*                                                                  */
  10561.  /* Provided this copyright notice is included, this software may    */
  10562.  /* be freely distributed and not offered for sale.                  */
  10563.  /*                                                                  */
  10564.  /* Changes or modifications may be made and used only by the maker  */
  10565.  /* of same, and not further distributed.  Such modifications should */
  10566.  /* be mailed to the author for consideration for addition to the    */
  10567.  /* software and incorporation in subsequent releases.               */
  10568.  /*                                                                  */
  10569.  /********************************************************************/
  10570.  
  10571. #pragma  csect(code,  "GG@FTP")
  10572. #pragma  csect(static,"GG$FTP")
  10573.  
  10574. #include "gg.h"
  10575.  
  10576.  /* Logic: use basic FTP protocol to get a directory or a file and
  10577.   *        write the results to the passed file pointer.
  10578.   *        Note: does not use PASV (win).
  10579.   */
  10580.  
  10581. #define  IPPORT_FTPD    20                /* FTP data port */
  10582. #define  IPPORT_FTP     21                /* FTP control port */
  10583. #define  SHOW(A)        fprintf(stderr,"%s\n",(A))
  10584. #define  BLATHER        if (F->verboseflag) fprintf
  10585. #define  FLOSE          cleanup(F); return(FALSE)
  10586. #define  FSEND(A,B)     if (!fsend(F,CS,(A),(B))) {FLOSE;}
  10587. #define  FRECV()        if (!frecv(F,CS,TRUE))    {FLOSE;}
  10588. #define  FEXPECT(A)     if (!fexpect(F,A))        {FLOSE;}
  10589.  
  10590. /* ---- Format an FTP port address. -------------------------------- */
  10591.  
  10592. static void
  10593. port_address(
  10594.              struct Ftp  *F,         /* needed by BLATHER macro */
  10595.              IPADDRESS    addrnum,
  10596.              int          portnum,
  10597.              char        *c
  10598.             )
  10599. {
  10600.  char                    *ap = (char *)&addrnum;
  10601.  char                    *pp = (char *)&portnum;
  10602.  
  10603.  BLATHER(stderr,"port_address: addrnum=%8.8X, portnum=%8.8X\n",
  10604.                 addrnum,portnum);
  10605.  
  10606.  sprintf(c,"%d,%d,%d,%d,%d,%d", (unsigned char)*(ap+0),
  10607.                                 (unsigned char)*(ap+1),
  10608.                                 (unsigned char)*(ap+2),
  10609.                                 (unsigned char)*(ap+3),
  10610.                                 (unsigned char)*(pp+2),
  10611.                                 (unsigned char)*(pp+3));
  10612.  
  10613.  return;
  10614. }
  10615.  
  10616. /* ---- Close socket. ---------------------------------------------- */
  10617.  
  10618. static Bool
  10619. ftp_close(
  10620.           struct Ftp  *F,
  10621.           SOCKETNO     s
  10622.          )
  10623. {
  10624.  
  10625.  BLATHER(stderr,"Closing socket %d\n",s);
  10626.  
  10627.  if (close(s) < 0) {
  10628.    REPORT_TCP_ERROR("close");
  10629.    return FALSE;
  10630.  }
  10631.  
  10632.  return TRUE;
  10633.  
  10634. }
  10635.  
  10636. /* ---- Connect to the FTP server host. ---------------------------- */
  10637.  
  10638. static SOCKETNO
  10639. ftp_connect(
  10640.             struct Ftp  *F,
  10641.             char        *ftphost
  10642.            )
  10643. {
  10644.  SOCKETNO                ftpsock;
  10645.  int                     bindrc;
  10646.  int                     listrc;
  10647.  int                     connrc;
  10648.  char                    ipstring[65];
  10649.  
  10650.  ftpsock = -1;
  10651.  gethostname(F->client_hostname,sizeof(F->client_hostname));
  10652.  F->client_hostent = gethostbyname(F->client_hostname);
  10653.  if (!F->client_hostent) {
  10654.    REPORT_TCP_ERROR("gethostbyname for client hostname");
  10655.    return -1;
  10656.  }
  10657.  F->hostaddress = *(IPADDRESS *)F->client_hostent->h_addr_list[0];
  10658.  
  10659.  SPRINTF_IP_ADDRESS(ipstring,F->hostaddress);
  10660.  BLATHER(stderr,"client %s [%s]\n",F->client_hostname,ipstring);
  10661.  
  10662.  ftpsock = socket(AF_INET, SOCK_STREAM, 0);
  10663.  if (ftpsock < 0) {
  10664.    REPORT_TCP_ERROR("socket");
  10665.    return -1;
  10666.  }
  10667.  
  10668.  F->bindsock.sin_family      = AF_INET;
  10669.  F->bindsock.sin_port        = 0;
  10670.  F->bindsock.sin_addr.s_addr = F->hostaddress;
  10671.  
  10672.  bindrc = Bind(ftpsock,&F->bindsock,sizeof(F->bindsock));
  10673.  if (bindrc < 0) {
  10674.    REPORT_TCP_ERROR("bind for client");
  10675.    return -1;
  10676.  }
  10677.  
  10678.  F->server_hostent = gethostbyname(ftphost);
  10679.  if (!F->server_hostent) {
  10680.    fprintf(F->errfp,"gethostbyname: unknown host %s\n",ftphost);
  10681.    return -1;
  10682.  }
  10683.  F->hostaddress = *(IPADDRESS *)F->server_hostent->h_addr;
  10684.  strcpy(F->server_hostname,ftphost);
  10685.  SPRINTF_IP_ADDRESS(ipstring,F->hostaddress);
  10686.  BLATHER(stderr,"server %s [%s]\n",F->server_hostname,ipstring);
  10687.  
  10688.  F->consock.sin_family      = AF_INET;
  10689.  F->consock.sin_port        = htons(IPPORT_FTP);
  10690.  F->consock.sin_addr.s_addr = F->hostaddress;
  10691.  
  10692.  connrc = Connect(ftpsock,&F->consock,sizeof(F->consock));
  10693.  if (connrc < 0) {
  10694.    REPORT_TCP_ERROR(ftphost);
  10695.    return -1;
  10696.  }
  10697.  
  10698.  return ftpsock;
  10699. }
  10700.  
  10701. /* --- Get a response from the FTP server. ------------------ */
  10702.  
  10703. static Bool
  10704. frecv(F,S,doread)
  10705. struct Ftp   *F;
  10706. CONNECTION   *S;
  10707. Bool          doread;
  10708. {
  10709.  
  10710.  S->dont_read = !doread;
  10711.  if (!GGgsrvl(NULL,S,NULL,NOCR)) return FALSE;
  10712.  if (S->time_to_go_home)    return FALSE;
  10713.  if (S->server_has_nothing) return TRUE;
  10714.  if (F->verboseflag) SHOW(S->server_buf);
  10715.  return TRUE;
  10716.  
  10717. }
  10718.  
  10719. /* --- Send a request to the FTP server. ----------------------- */
  10720.  
  10721. static Bool
  10722. fsend(F,S,text,arg)
  10723. struct Ftp  *F;
  10724. CONNECTION  *S;
  10725. char        *text;
  10726. char        *arg;
  10727. {
  10728.  
  10729.  /* check if there's anything pending from the server before sending */
  10730.  
  10731.  (void)frecv(F,S,FALSE);
  10732.  sprintf(S->client_buf,text,arg);
  10733.  if (F->verboseflag) SHOW(S->client_buf);
  10734.  return GGsockt(NULL,S);
  10735. }
  10736.  
  10737. /* --- Retrieve a response and insure it was the expected one. -- */
  10738.  
  10739. static Bool
  10740. fexpect(F,mesid)
  10741. struct Ftp   *F;
  10742. char         *mesid;
  10743. {
  10744.  CONNECTION  *S = &F->control_connection;
  10745.  
  10746.  for (;;) {
  10747.    if (!frecv(F,S,TRUE)) return FALSE;
  10748.    if (S->server_buf[0] == '\0') continue;
  10749.    if (S->server_buf[0] == ' ')  continue;
  10750.    if (strlen(S->server_buf) > 3) {
  10751.      if (!memcmp(mesid,S->server_buf,3)) {
  10752.        if (S->server_buf[3] == '-')  continue;
  10753.        if (S->server_buf[3] == '\0') break;
  10754.        if (S->server_buf[3] == ' ')  break;
  10755.      }
  10756.    }
  10757.    fprintf(F->errfp,"Unexpected FTP response from %s:\n%s\n",
  10758.                     F->server_hostname, S->server_buf);
  10759.    return FALSE;
  10760.  }
  10761.  
  10762.  return TRUE;
  10763. }
  10764.  
  10765. /*================================================================*/
  10766.  
  10767. static GOPHERTYPE
  10768. viewtype(char *fname)
  10769. {
  10770.  int           len = strlen(fname);
  10771.  int           i;
  10772.  
  10773. #define SUFFIX_TO_TYPE(A,B)  i = sizeof(A)-1; \
  10774.                              if (len > i && !memcmp(fname+len-i,A,i)) \
  10775.                                 return B;
  10776.  
  10777.  SUFFIX_TO_TYPE(".gif"  ,GOPHER_IMAGE);
  10778.  SUFFIX_TO_TYPE(".pict" ,GOPHER_IMAGE);
  10779.  SUFFIX_TO_TYPE(".tiff" ,GOPHER_IMAGE);
  10780.  SUFFIX_TO_TYPE(".jpg"  ,GOPHER_IMAGE);
  10781.  SUFFIX_TO_TYPE(".jpeg" ,GOPHER_IMAGE);
  10782.  SUFFIX_TO_TYPE(".hqx"  ,GOPHER_MAC_BINHEX);
  10783.  SUFFIX_TO_TYPE(".arc"  ,GOPHER_BINARY);
  10784.  SUFFIX_TO_TYPE(".exe"  ,GOPHER_BINARY);
  10785.  SUFFIX_TO_TYPE(".EXE"  ,GOPHER_BINARY);
  10786.  SUFFIX_TO_TYPE(".gz"   ,GOPHER_BINARY);
  10787.  SUFFIX_TO_TYPE(".gzip" ,GOPHER_BINARY);
  10788.  SUFFIX_TO_TYPE(".hqx"  ,GOPHER_BINARY);
  10789.  SUFFIX_TO_TYPE(".snd"  ,GOPHER_BINARY);
  10790.  SUFFIX_TO_TYPE(".tar"  ,GOPHER_BINARY);
  10791.  SUFFIX_TO_TYPE(".Z"    ,GOPHER_BINARY);
  10792.  SUFFIX_TO_TYPE(".zip"  ,GOPHER_BINARY);
  10793.  SUFFIX_TO_TYPE(".zoo"  ,GOPHER_BINARY);
  10794.  
  10795.  return GOPHER_FILE;
  10796. }
  10797.  
  10798. /*================================================================*/
  10799.  
  10800. static Bool
  10801. ls_to_gopher(struct Ftp *F,
  10802.              char       *buf,
  10803.              int        *lenp
  10804.             )
  10805.  
  10806. {
  10807. #define     NUMBER_OF_WORDS  12
  10808.  char      *outnamep;
  10809.  char      *word[NUMBER_OF_WORDS];
  10810.  char      *cp;
  10811.  char      *ep;
  10812.  char      *name;
  10813.  char      *symlink;
  10814.  char       mode;
  10815.  int        i;
  10816.  int        maxwords;
  10817.  char       outtype;
  10818.  char       vmname  [ 33];
  10819.  char       empath  [513];
  10820.  char       rfile   [513];
  10821.  char       outname [513];
  10822.  char       outpath [513];
  10823.  
  10824.  for (i = 0; i < NUMBER_OF_WORDS; i++) word[i] = "";
  10825.  
  10826.  /* Loop setting word[...] pointers to words in the buffer. */
  10827.  
  10828.  buf[*lenp] = '\0';
  10829.  
  10830.  /* Count the number of whitespace-delimited words on the line. */
  10831.  
  10832.  for (i = 0, cp = skip_whitespace(buf);
  10833.       i < NUMBER_OF_WORDS;
  10834.       cp = skip_whitespace(ep)) {
  10835.    word[i++] = cp;
  10836.    ep = strchr(cp,' ');
  10837.    if (!ep) break;
  10838.  }
  10839.  
  10840.  maxwords = i;
  10841.  
  10842.  /*
  10843.   * Normal Unix-style ls output:
  10844.   *
  10845.   * 0     1     2     3     4     5     6    7
  10846.   * mode  block user  size  month day   time name
  10847.   *
  10848.   * or
  10849.   *
  10850.   * 0     1     2     3     4     5     6    7     8
  10851.   * mode  block user  group size  month day  time  name
  10852.   *
  10853.   * or
  10854.   *
  10855.   * 0     1     2     3     4     5     6    7     8     9    10
  10856.   * mode  block user  group size  month day  time  name  -->  real
  10857.   *
  10858.   *
  10859.   * VM/CMS server output:
  10860.   *
  10861.   * 0     1     2     3     4     5     6    7     8
  10862.   * fname fmode ftype stuff stuff stuff date time  disk?
  10863.   *
  10864.   */
  10865.  
  10866.  if (maxwords < 8) return FALSE;
  10867.  else if (F->os == VM_OS) {
  10868.    if ((ep=strchr(word[0],' '))) *ep = '\0';
  10869.    if ((ep=strchr(word[1],' '))) *ep = '\0';
  10870.    sprintf(vmname,"%s.%s",word[0],word[1]);
  10871.    mode    = '-';
  10872.    name    = vmname;
  10873.    symlink = "";
  10874.  }
  10875.  else {
  10876.    mode = *word[0];
  10877.    symlink = "";
  10878.    if      (maxwords == 8)     name = word[7];
  10879.    else if (isdigit(*word[4])) name = word[8];
  10880.    else                        name = word[7];
  10881.    if (mode == 'l' || mode == 'L') {
  10882.      ep = strstr(name," -> ");
  10883.      if (ep) {
  10884.        *ep = '\0';
  10885.        symlink = skip_whitespace(ep+3);
  10886.      }
  10887.    }
  10888.  }
  10889.  
  10890.  BLATHER(stderr,"maxwords=%d,name=%s,mode=%c,symlink=%s\n",
  10891.                 maxwords,name,mode,symlink);
  10892.  
  10893.  if (!*name) return FALSE;
  10894.  
  10895. #define PATH_SIZE_LIMIT 40
  10896.  
  10897.  if (strlen(F->path) > PATH_SIZE_LIMIT) {
  10898.    strcpy(empath, F->path + strlen(F->path) - PATH_SIZE_LIMIT);
  10899.  }
  10900.  else {
  10901.    strcpy(empath, F->path);
  10902.  }
  10903.  
  10904.  /*
  10905.   * Replace a symbolic link by the file to which it points.  E.g.:
  10906.   *
  10907.   * /any-path     ->  /absolute/path      ==>  /absolute/path
  10908.   * /foo/bar/baz  ->  relative/path       ==>  /foo/bar/relative/path
  10909.   * /foo/bar/baz/ ->  relative/path       ==>  /foo/bar/relative/path
  10910.   * foobar        ->  relative/path       ==>  relative/path
  10911.   *
  10912.   */
  10913.  
  10914.  if (*symlink) {
  10915.    if (symlink[0] == '/')  strcpy(rfile,symlink);
  10916.    else {
  10917.      if (name[0] == '/')     strcpy(rfile,name);
  10918.      else                    sprintf(rfile,"%s/%s",F->path,name);
  10919.      /* strcpy(rfile,F->path); */
  10920.      cp = strrchr(rfile,'/');
  10921.      if (cp && *(cp+1) == '\0') {
  10922.        *cp = '\0';
  10923.        cp = strrchr(rfile,'/');
  10924.      }
  10925.      if (!cp) cp = rfile-1;
  10926.      strcpy(cp+1,symlink);
  10927.    }
  10928.    sprintf(outname,"%s: %s:     %s -> %s",F->host,empath,name,symlink);
  10929.  }
  10930.  else {
  10931.    if (name[0] == '/')     strcpy(rfile,name);
  10932.    else                    sprintf(rfile,"%s/%s",F->path,name);
  10933.    sprintf(outname,"%s: %s:     %s",F->host,empath,name);
  10934.  }
  10935.  
  10936.  switch (mode) {
  10937.    case '-': outtype = viewtype(rfile); break;
  10938.    case 'd':
  10939.    case 'D': outtype = GOPHER_MENU; break;
  10940.    case 'l':
  10941.    case 'L': outtype = GOPHER_MENU; break;
  10942.    default:  BLATHER(stderr,"Unknown mode '%c'\n",mode); return FALSE;
  10943.  }
  10944.  
  10945.  if (strlen(outname) > 255) outnamep = outname + strlen(outname) - 255;
  10946.  else                       outnamep = outname;
  10947.  
  10948.  sprintf(outpath,"%s%c:%s:%s:%s:%s",
  10949.                  F->ftphack, outtype, F->host, F->user, F->pass, rfile);
  10950.  
  10951.  sprintf(buf,"%c%s\t%s\t%s\t%d\n",
  10952.              outtype, outnamep, outpath, F->myname, F->myport);
  10953.  
  10954.  (*lenp) = strlen(buf);
  10955.  
  10956.  return TRUE;
  10957. }
  10958.  
  10959. /*================================================================*/
  10960.  
  10961. static int
  10962. emit(struct Ftp *F,
  10963.      char       *buf,
  10964.      int         len
  10965.     )
  10966. {
  10967.  int             fwriterc;
  10968.  Bool            got_a_record;
  10969.  char            newbuf [23448];
  10970.  
  10971.    memcpy(newbuf,buf,len);
  10972.  
  10973.    if (F->listflag) {
  10974.      got_a_record = ls_to_gopher(F,newbuf,&len);
  10975.    }
  10976.    else if (F->binary) {
  10977.      got_a_record = TRUE;
  10978.    }
  10979.    else {
  10980.      newbuf[len++] = '\n';
  10981.      got_a_record = TRUE;
  10982.    }
  10983.    if (got_a_record) {
  10984.      fwriterc = fwrite(newbuf,1,len,F->outfp);
  10985.      if (fwriterc < len) {
  10986.        fprintf(stderr,"Error writing to FTP output file\n");
  10987.      }
  10988.    }
  10989.    else fwriterc = 0;
  10990.  
  10991.    return fwriterc;
  10992.  
  10993. }
  10994.  
  10995. /*================================================================*/
  10996.  
  10997. static void
  10998. cleanup(struct Ftp *F)
  10999. {
  11000.  CONNECTION        *CS = &F->control_connection;
  11001.  CONNECTION        *DS = &F->data_connection;
  11002.  
  11003.  if (F->listen_socket_opened) {
  11004.    (void)ftp_close(F,F->listensocket);
  11005.    F->listen_socket_opened = FALSE;
  11006.  }
  11007.  
  11008.  if (F->accept_socket_opened) {
  11009.    (void)ftp_close(F,DS->ns);
  11010.    F->accept_socket_opened = FALSE;
  11011.  }
  11012.  
  11013.  if (F->control_socket_opened) {
  11014.    (void)ftp_close(F,CS->ns);
  11015.    F->control_socket_opened = FALSE;
  11016.  }
  11017.  
  11018. }
  11019.  
  11020. /*================================================================*/
  11021.  
  11022. Bool
  11023. GGftp(RECV        *R,
  11024.       struct Ftp  *F
  11025.      )
  11026. {
  11027.  CONNECTION          *CS = &F->control_connection;
  11028.  CONNECTION          *DS = &F->data_connection;
  11029.  char                *ftpgetf = NULL;
  11030.  char                *ftproot = NULL;
  11031.  char                *cp;
  11032.  Bool                 rc = FALSE;
  11033.  int                  socksize;
  11034.  int                  accept_count;
  11035.  int                  bytes_to_write;
  11036.  int                  fwriterc;
  11037.  int                  bytes_written;
  11038.  IOMODE               crmode;
  11039.  struct sockaddr_in   datasocket;
  11040.  struct sockaddr_in   controlsocket;
  11041.  char                 port                  [81];
  11042.  char                 control_server_buffer [SERVER_BUF_MSGSIZE+4];
  11043.  char                 data_server_buffer    [SERVER_BUF_MSGSIZE+4];
  11044.  char                 control_client_buffer [CLIENT_BUF_MSGSIZE+4];
  11045.  char                 data_client_buffer    [CLIENT_BUF_MSGSIZE+4];
  11046.  
  11047.  CLEAR(&datasocket);
  11048.  CLEAR(&controlsocket);
  11049.  CS->buf_index  = -1;
  11050.  DS->buf_index  = -1;
  11051.  CS->is_ftp     = TRUE;
  11052.  DS->is_ftp     = TRUE;
  11053.  CS->server_buf = control_server_buffer;
  11054.  DS->server_buf = data_server_buffer;
  11055.  CS->client_buf = control_client_buffer;
  11056.  DS->client_buf = data_client_buffer;
  11057.  F->myname      = R->myname;
  11058.  F->myport      = R->myport;
  11059.  F->control_socket_opened = FALSE;
  11060.  F->listen_socket_opened  = FALSE;
  11061.  F->accept_socket_opened  = FALSE;
  11062.  
  11063.  switch (F->type) {
  11064.    case GOPHER_DIRECTORY:
  11065.                          F->listflag = TRUE;  F->binary = FALSE; break;
  11066.    case GOPHER_MAC_BINHEX:
  11067.    case GOPHER_DOS_BINARCH:
  11068.    case GOPHER_IMAGE:
  11069.    case GOPHER_BINARY:
  11070.    case GOPHER_BOOKMANAGER:
  11071.                          F->listflag = FALSE; F->binary = TRUE;  break;
  11072.    case GOPHER_FILE:
  11073.    default:
  11074.                          F->listflag = FALSE; F->binary = FALSE; break;
  11075.  }
  11076.  
  11077.  switch (F->os) {
  11078.    case VM_OS: if ((cp=strchr(F->path,'/'))) {
  11079.                 *cp = '\0';
  11080.                 ftproot = F->path;
  11081.                 ftpgetf = cp + 1;
  11082.                }
  11083.                else {
  11084.                 ftproot = F->path;
  11085.                 ftpgetf = "";
  11086.                }
  11087.                break;
  11088.    default:    ftproot = "";
  11089.                ftpgetf = F->path;
  11090.                break;
  11091.  }
  11092.  
  11093.  CS->ns = ftp_connect(F,F->host);
  11094.  if (CS->ns < 0) {FLOSE;}
  11095.  F->control_socket_opened = TRUE;
  11096.  
  11097.  BLATHER(stderr,"Connected to %s (socket %d).\n", F->host, CS->ns);
  11098.  
  11099.  FEXPECT("220");  /* server ready */
  11100.  
  11101.  FSEND("USER %s",F->user);
  11102.  FEXPECT("331");  /* password required */
  11103.  
  11104.  FSEND("PASS %s",F->pass);
  11105.  FEXPECT("230");  /* user logged in */
  11106.  
  11107.  /* must issue RETR command but open data connection first */
  11108.  
  11109.  F->listensocket = socket(AF_INET, SOCK_STREAM, 0);
  11110.  if (F->listensocket < 0) {
  11111.    REPORT_TCP_ERROR("data socket");
  11112.    FLOSE;
  11113.  }
  11114.  F->listen_socket_opened = TRUE;
  11115.  
  11116.  listen(F->listensocket,1); /* accept only one connection */
  11117.  
  11118.  /* get port number of data connection */
  11119.  
  11120.  socksize = sizeof(struct sockaddr);
  11121.  Getsockname(F->listensocket,&datasocket,&socksize);
  11122.  socksize = sizeof(struct sockaddr);
  11123.  Getsockname(CS->ns,&controlsocket,&socksize);
  11124.  datasocket.sin_addr.s_addr = controlsocket.sin_addr.s_addr;
  11125.  
  11126.  port_address(F,datasocket.sin_addr.s_addr,datasocket.sin_port,port);
  11127.  
  11128.  FSEND("PORT %s", port);
  11129.  FEXPECT("200");  /* command successful */
  11130.  
  11131.  if (F->binary) {
  11132.    crmode = RBIN;
  11133.    FSEND("TYPE %s","I");          /* image type */
  11134.  }
  11135.  else {
  11136.    crmode = NOCR;
  11137.    FSEND("TYPE %s","A");          /* ascii type */
  11138.  }
  11139.  FEXPECT("200");  /* type set to ... */
  11140.  
  11141.  if (*ftproot) {
  11142.    FSEND("CWD %s", ftproot);
  11143.    FEXPECT("250");  /* current working dir set to ... */
  11144.  }
  11145.  
  11146.  if (F->listflag) {
  11147.    if (!*ftpgetf) {FSEND("LIST", NULL);}
  11148.    else           {FSEND("LIST %s", ftpgetf);}
  11149.  }
  11150.  else if (F->nlstflag) {
  11151.    if (!*ftpgetf) {FSEND("NLST", NULL);}
  11152.    else           {FSEND("NLST %s", ftpgetf);}
  11153.  }
  11154.  else {
  11155.    FSEND("RETR %s", ftpgetf);
  11156.  }
  11157.  if (F->os == VM_OS && (F->listflag || F->nlstflag)) {
  11158.    FEXPECT("125");  /* List started OK */
  11159.  }
  11160.  else {
  11161.    FEXPECT("150");  /* data connection for... */
  11162.  }
  11163.  
  11164.  accept_count = 0;
  11165.  DS->ns = Accept(F->listensocket,NULL,&accept_count);
  11166.  if (DS->ns < 0) {
  11167.    REPORT_TCP_ERROR("accept");
  11168.    FLOSE;
  11169.  }
  11170.  F->accept_socket_opened = TRUE;
  11171.  
  11172.  /* get data from data connection */
  11173.  
  11174.  bytes_to_write = 0;
  11175.  bytes_written = 0;
  11176.  DS->time_to_go_home = FALSE;
  11177.  DS->server_has_nothing = FALSE;
  11178.  for (;;) {
  11179.    if (!GGgsrvl(NULL,DS,NULL,crmode)) {FLOSE;}
  11180.    if (DS->time_to_go_home || DS->server_has_nothing) break;
  11181.    if (crmode == RBIN) bytes_to_write = DS->nbytes;
  11182.    else                bytes_to_write = strlen(DS->server_buf)-1;
  11183.    fwriterc = emit(F,DS->server_buf,bytes_to_write);
  11184.    bytes_written += fwriterc;
  11185.  }
  11186.  
  11187.  /* Close the data socket before waiting for the server to return
  11188.   * connection acknowledgement.  The VM server enforces this.
  11189.   */
  11190.  
  11191.  (void)ftp_close(F,DS->ns);
  11192.  F->accept_socket_opened = FALSE;
  11193.  
  11194.  if (F->os == VM_OS) {
  11195.    FEXPECT("250");  /* ... completed successfully */
  11196.  }
  11197.  else {
  11198.    FEXPECT("226");  /* transfer complete */
  11199.  }
  11200.  
  11201.  FSEND("QUIT",NULL);
  11202.  FEXPECT("221");  /* goodbye */
  11203.  
  11204.  cleanup(F);
  11205.  return TRUE;
  11206.  
  11207. }
  11208.  
  11209. ./ ADD NAME=GGGETDS
  11210.  
  11211.  /********************************************************************/
  11212.  /*                                                                  */
  11213.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  11214.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  11215.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  11216.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  11217.  /*                                                                  */
  11218.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  11219.  /* including the implied warranties of merchantability and fitness, */
  11220.  /* are expressly denied.                                            */
  11221.  /*                                                                  */
  11222.  /* Provided this copyright notice is included, this software may    */
  11223.  /* be freely distributed and not offered for sale.                  */
  11224.  /*                                                                  */
  11225.  /* Changes or modifications may be made and used only by the maker  */
  11226.  /* of same, and not further distributed.  Such modifications should */
  11227.  /* be mailed to the author for consideration for addition to the    */
  11228.  /* software and incorporation in subsequent releases.               */
  11229.  /*                                                                  */
  11230.  /********************************************************************/
  11231.  
  11232. #pragma  csect(code,  "GG@GETDS")
  11233. #pragma  csect(static,"GG$GETDS")
  11234. #include "gg.h"
  11235. #include "ggsvc99.h"
  11236.  
  11237. /****** Function to close sequential data set after extraction. ******/
  11238.  
  11239. static void
  11240. close_seq(gp,ep,xfp,final)
  11241. RGGCB       *gp;
  11242. EXTRACTION  *ep;
  11243. FILE        *xfp;
  11244. Fool         final;
  11245. {
  11246.  
  11247.  if (fclose(xfp) < 0) {
  11248.    /* perror(ep->dsname); */
  11249.    ERR2("An error occurred closing %s.", ep->dsname);
  11250.    gp->extract_close_error = TRUE;
  11251.  }
  11252.  
  11253. }
  11254.  
  11255. /****** Function to close partitioned data set after extraction. *****/
  11256.  
  11257. static void
  11258. close_pds(gp,ep,xfp,final)
  11259. RGGCB       *gp;
  11260. EXTRACTION  *ep;
  11261. FILE        *xfp;
  11262. Fool         final;
  11263. {
  11264.  
  11265.  if (final) {
  11266.    (void)GGunalc(ep->ddname);     /* Unallocate the PDS */
  11267.  }
  11268.  else {
  11269.    if (fclose(xfp) < 0) {
  11270.      /* perror(ep->dsname); */
  11271.      ERR2("An error occurred closing %s.", ep->dsname);
  11272.      gp->extract_close_error = TRUE;
  11273.    }
  11274.  }
  11275.  
  11276. }
  11277.  
  11278. /****** Function to close SYSOUT print file after printing. **********/
  11279.  
  11280. static void
  11281. close_jes(gp,ep,xfp,final)
  11282. RGGCB       *gp;
  11283. EXTRACTION  *ep;
  11284. FILE        *xfp;
  11285. Fool         final;
  11286. {
  11287.  
  11288.  if (fclose(xfp) < 0) {
  11289.    /* perror(ep->dsname); */
  11290.    ERR2("An error occurred closing %s.", ep->dsname);
  11291.    gp->extract_close_error = TRUE;
  11292.  }
  11293.  if (final) {
  11294.    (void)GGunalc(ep->ddname);     /* Unallocate the SYSOUT file */
  11295.  }
  11296.  
  11297. }
  11298.  
  11299. /****** Allocate SYSOUT file. ****************************************/
  11300.  
  11301. static Bool
  11302. allocate_sysout(ep,sp)
  11303. register EXTRACTION   *ep;
  11304. register SYSOUT       *sp;
  11305. {
  11306.  int          i;
  11307.  int          rc;
  11308.  char        *cp;
  11309.  __S99parms   stuff99;   /* The manual has it wrong.  No "struct". */
  11310.  TEXTUNIT    *tu [ 8];
  11311.  TEXTUNIT     tu_sysout;
  11312.  TEXTUNIT     tu_copies;
  11313.  TEXTUNIT     tu_dest;
  11314.  TEXTUNIT     tu_userid;
  11315.  TEXTUNIT     tu_forms;
  11316.  TEXTUNIT     tu_ucs;
  11317.  TEXTUNIT     tu_rtddn;
  11318.  
  11319.  CLEAR(&stuff99);
  11320.  
  11321.  stuff99.__S99RBLN   = 20;
  11322.  stuff99.__S99VERB   = S99VRBAL;
  11323.  stuff99.__S99FLAG1  = S99NOCNV << 8;
  11324.  stuff99.__S99ERROR  = 0;
  11325.  stuff99.__S99INFO   = 0;
  11326.  stuff99.__S99TXTPP  = tu;
  11327.  stuff99.__S99FLAG2  = 0;
  11328.  
  11329.  i = 0;
  11330.  
  11331.  tu[i++] = &tu_sysout;
  11332.  
  11333.  tu_sysout.key        = DALSYSOU;
  11334.  tu_sysout.num        = 1;
  11335.  tu_sysout.ent.len    = 1;
  11336.  tu_sysout.ent.prm[0] = toupper(sp->class[0]);
  11337.  
  11338.  tu[i++] = &tu_copies;
  11339.  
  11340.  tu_copies.key        = DALCOPYS;
  11341.  tu_copies.num        = 1;
  11342.  tu_copies.ent.len    = 1;
  11343.  tu_copies.ent.prm[0] = (unsigned char)sp->copies;
  11344.  
  11345.  if (sp->dest[0] > ' ') {
  11346.  
  11347.   tu[i++] = &tu_dest;
  11348.  
  11349.   tu_dest.key          = DALSUSER;
  11350.   tu_dest.num          = 1;
  11351.   copy_uppercase_and_strip_trailing(tu_dest.ent.prm,sp->dest,cp);
  11352.   tu_dest.ent.len      = cp - tu_dest.ent.prm;
  11353.  
  11354.  }
  11355.  
  11356.  if (sp->userid[0] > ' ') {
  11357.  
  11358.   tu[i++] = &tu_userid;
  11359.  
  11360.   tu_userid.key        = DALUSRID;
  11361.   tu_userid.num        = 1;
  11362.   copy_uppercase_and_strip_trailing(tu_userid.ent.prm,sp->userid,cp);
  11363.   tu_userid.ent.len    = cp - tu_userid.ent.prm;
  11364.  
  11365.  }
  11366.  
  11367.  if (sp->forms[0] > ' ') {
  11368.  
  11369.   tu[i++] = &tu_forms;
  11370.  
  11371.   tu_forms.key         = DALSFMNO;
  11372.   tu_forms.num         = 1;
  11373.   copy_uppercase_and_strip_trailing(tu_forms.ent.prm,sp->forms,cp);
  11374.   tu_forms.ent.len     = cp - tu_forms.ent.prm;
  11375.  
  11376.  }
  11377.  
  11378.  if (sp->ucs[0] > ' ') {
  11379.  
  11380.   tu[i++] = &tu_ucs;
  11381.  
  11382.   tu_ucs.key           = DALUCS;
  11383.   tu_ucs.num           = 1;
  11384.   copy_uppercase_and_strip_trailing(tu_ucs.ent.prm,sp->ucs,cp);
  11385.   tu_ucs.ent.len       = cp - tu_ucs.ent.prm;
  11386.  
  11387.  }
  11388.  
  11389.  tu[i++] = &tu_rtddn;
  11390.  
  11391.  tu_rtddn.key         = DALRTDDN;
  11392.  tu_rtddn.num         = 1;
  11393.  tu_rtddn.ent.len     = 8;
  11394.  memset(tu_rtddn.ent.prm,' ',8);
  11395.  
  11396.  tu[i] = (void *)0x80000000;
  11397.  
  11398.  rc = svc99(&stuff99);
  11399.  
  11400.  if (rc == 0) {
  11401.    memcpy(ep->ddname,(char *)tu_rtddn.ent.prm,8);
  11402.    ep->ddname[8] = ' ';
  11403.    *(strchr(ep->ddname,' ')) = '\0';
  11404.    return TRUE;
  11405.  }
  11406.  else {
  11407.    GGdfail(rc,&stuff99);
  11408.    return FALSE;
  11409.  }
  11410. }
  11411.  
  11412. /****** Prompt user for the name of a data set to extract into. ******/
  11413.  
  11414. FILE *
  11415. GGgetds(gp,ep)
  11416. RGGCB  *gp;
  11417. REXTR  *ep;
  11418. {
  11419.  FILE       *xfp;
  11420.  char       *bufptr;
  11421.  Bool        asked_for;
  11422.  Bool        do_warn;
  11423.  Bool        is_not_gopher_menu;
  11424.  SYSOUT      sys;
  11425.  char        ggexdsn [65];    /* data set name for extraction  */
  11426.  char        ggbmdsn [65];    /* data set name for bookmark    */
  11427.  char        ggexapp  [4];    /* YES or NO for append mode     */
  11428.  char        ggextab  [4];    /* YES or NO for tab expansion   */
  11429.  char        ggexblk  [4];    /* YES or NO for blank after sep */
  11430.  char        ggexsep [81];    /* Separator line (optional)     */
  11431.  char        ggexpmp  [9];    /* PDS member name prefix        */
  11432.  char        ggexscl  [2];    /* Print SYSOUT class name       */
  11433.  char        ggexsco  [4];    /* Print SYSOUT copies number    */
  11434.  char        ggexsde [18];    /* Print SYSOUT destination      */
  11435.  char        ggexsus [18];    /* Print SYSOUT userid           */
  11436.  char        ggexsfo  [5];    /* Print SYSOUT forms            */
  11437.  char        ggexsuc  [5];    /* Print SYSOUT UCS              */
  11438.  char        ddname   [9];
  11439.  char        member   [9];
  11440.  char        pdspec  [32];
  11441.  char        quoted_dsname [67];
  11442.  char        formatted_number [11];
  11443.  char        buffer [RBUFSIZE];
  11444.  
  11445.  xfp = NULL;
  11446.  asked_for = TRUE;
  11447.  
  11448. #ifdef FULLSYSOUT
  11449.  VPUT("GGALLPR ","Y");
  11450. #else
  11451.  VPUT("GGALLPR ","");
  11452. #endif
  11453.  
  11454.  ISPF("ADDPOP");
  11455.  
  11456.  while (!xfp) {
  11457.  
  11458.    /* Keep asking for a dsname until one works or END pressed. */
  11459.  
  11460.    if (GGdispl(gp,ep->panelname) > 0) {
  11461.      WARN1("Request cancelled, because you pressed END.");
  11462.      asked_for = FALSE;
  11463.      xfp = NULL;
  11464.      break;
  11465.    }
  11466.  
  11467.    switch (ep->ex) {
  11468.      case EXTRACT_IT:
  11469.                       VGET("GGEXDSN ",ggexdsn);
  11470.                       VGET("GGEXTAB ",ggextab);
  11471.                       if (ep->mode == PDS) {
  11472.                         VGET("GGEXPMP ",ggexpmp);
  11473.                       }
  11474.                       else {
  11475.                         VGET("GGEXAPP ",ggexapp);
  11476.                         VGET("GGEXBLK ",ggexblk);
  11477.                         VGET("GGEXSEP ",ggexsep);
  11478.                       }
  11479.                       break;
  11480.      case PRINT_IT:
  11481.                       VGET("GGEXSCL ",ggexscl);
  11482.                       VGET("GGEXSCO ",ggexsco);
  11483. #ifdef FULLSYSOUT
  11484.                       VGET("GGEXSDE ",ggexsde);
  11485.                       VGET("GGEXSUS ",ggexsus);
  11486.                       VGET("GGEXSFO ",ggexsfo);
  11487.                       VGET("GGEXSUC ",ggexsuc);
  11488. #else
  11489.                       *ggexsde = '\0';
  11490.                       *ggexsus = '\0';
  11491.                       *ggexsfo = '\0';
  11492.                       *ggexsuc = '\0';
  11493. #endif
  11494.                       VGET("GGEXBLK ",ggexblk);
  11495.                       VGET("GGEXSEP ",ggexsep);
  11496.                       break;
  11497.      case BOOKMARK_IT:
  11498.                       VGET("GGBMDSN ",ggbmdsn);
  11499.                       break;
  11500.    }
  11501.  
  11502.    if (ep->mode == PDS) {
  11503.  
  11504.      ep->closer = close_pds;
  11505.      ep->appending = FALSE;
  11506.      ep->blanking  = FALSE;
  11507.      strcpy(ep->separator,"");
  11508.      strcpy(ep->ddname,"");
  11509.      strcpy(ep->member_prefix,ggexpmp);
  11510.  
  11511.      /* Note: panel forces fully-qualified name to pass to allocate */
  11512.  
  11513.      if (ggexdsn[0] != '\'') {
  11514.        strcpy(quoted_dsname,"'");
  11515.        strcat(quoted_dsname,ggexdsn);
  11516.        strcat(quoted_dsname,"'");
  11517.      }
  11518.      else strcpy(quoted_dsname,ggexdsn);
  11519.  
  11520.      /* Check if PDS already exists. */
  11521.  
  11522.      if (gp->warn_overwrite) {
  11523.        if (TEST_IF_FILE_EXISTS(xfp,quoted_dsname)) {
  11524.          CLEANUP_IF_FILE_EXISTS(xfp);
  11525.          xfp = NULL;
  11526.          if (GGdispl(gp,"GGMPEXPW") > 0) {
  11527.            WARN1("Operation cancelled, because you pressed END.");
  11528.            break;
  11529.          }
  11530.        }
  11531.      }
  11532.  
  11533.      if (GGalloc(ggexdsn,ep->ddname,PDS,ep->count) != PDS) {
  11534.        ERR2("Allocation failed for data set %s.", ggexdsn);
  11535.        xfp = NULL;
  11536.        continue;
  11537.      }
  11538.      strcpy(ep->dsname, ggexdsn);
  11539.      ep->tab_expanding = (ggextab[0] == 'Y');
  11540.      do_warn = (ep->appending ? gp->warn_append : gp->warn_overwrite);
  11541.    }
  11542.    else if (ep->mode == JES) {
  11543.      if (strlen(ggexsde) > 8) {
  11544.        ERR2("SYSOUT destination is too long: %s", ggexsde);
  11545.        xfp = NULL;
  11546.        continue;
  11547.      }
  11548.      if (strlen(ggexsus) > 8) {
  11549.        ERR2("SYSOUT userid is too long: %s", ggexsus);
  11550.        xfp = NULL;
  11551.        continue;
  11552.      }
  11553.      ep->closer = close_jes;
  11554.      strcpy(ep->separator, ggexsep);
  11555.      sprintf(ep->dsname,"SYSOUT class %s",ggexscl);
  11556.      strcpy(sys.class, ggexscl);
  11557.      sys.copies = atoi(ggexsco);
  11558.      if (sys.copies < 1) sys.copies = 1;
  11559.      strcpy(sys.dest,  ggexsde);
  11560.      strcpy(sys.userid,ggexsus);
  11561.      strcpy(sys.forms, ggexsfo);
  11562.      strcpy(sys.ucs,   ggexsuc);
  11563.      ep->appending     = FALSE;
  11564.      ep->blanking      = (ggexblk[0] == 'Y');
  11565.      ep->tab_expanding = TRUE;
  11566.      do_warn = FALSE;
  11567.    }
  11568.    else if (ep->ex == BOOKMARK_IT) {
  11569.      ep->closer = close_seq;
  11570.      strcpy(ep->separator, "");
  11571.      strcpy(ep->dsname,    ggbmdsn);
  11572.      strcpy(ggexdsn,       ggbmdsn);
  11573.      ep->appending       = TRUE;
  11574.      ep->blanking        = FALSE;
  11575.      ep->tab_expanding   = FALSE;
  11576.      do_warn = FALSE;
  11577.    }
  11578.    else {
  11579.      ep->closer = close_seq;
  11580.      strcpy(ep->separator, ggexsep);
  11581.      strcpy(ep->dsname,    ggexdsn);
  11582.      ep->appending      = (ggexapp[0] == 'Y');
  11583.      ep->blanking       = (ggexblk[0] == 'Y');
  11584.      ep->tab_expanding  = (ggextab[0] == 'Y');
  11585.      do_warn = (ep->appending ? gp->warn_append : gp->warn_overwrite);
  11586.    }
  11587.  
  11588.    /* check if the dataset already exists */
  11589.  
  11590.    if (ep->ex == BOOKMARK_IT) {
  11591.      is_not_gopher_menu = FALSE;
  11592.      if (TEST_IF_FILE_EXISTS(xfp,ggexdsn)) {
  11593.        /* check that it is a gopher menu */
  11594.        CLEANUP_IF_FILE_EXISTS(xfp);
  11595.        xfp = fopen(ggexdsn,"r");
  11596.        if (xfp) {
  11597.          *buffer = '\0';
  11598.          fgets(buffer,sizeof(buffer),xfp);
  11599.          if (*buffer) {
  11600.            if ((bufptr=strchr(buffer,'\n'))) *bufptr = '\0';
  11601.            uppercase_in_place(buffer);
  11602.            bufptr = skip_whitespace(buffer);
  11603.            if (!EQUAL(bufptr,MENUIDENT)) is_not_gopher_menu = TRUE;
  11604.          }
  11605.          (void)fclose(xfp);
  11606.          xfp = NULL;
  11607.        }
  11608.        if (is_not_gopher_menu) {
  11609.          WARN2("Not a gopher bookmark or menu file: %s",ep->dsname);
  11610.          break;
  11611.        }
  11612.        ep->appending = TRUE;
  11613.      }
  11614.      else {
  11615.        ep->appending = FALSE;
  11616.      }
  11617.    }
  11618.    else if (ep->mode != JES) {
  11619.      if (do_warn) {
  11620.        if (TEST_IF_FILE_EXISTS(xfp,ggexdsn)) {
  11621.          CLEANUP_IF_FILE_EXISTS(xfp);
  11622.          xfp = NULL;
  11623.          if (GGdispl(gp,"GGMPEXOW") > 0) {
  11624.            WARN1("Operation cancelled, because you pressed END.");
  11625.            break;
  11626.          }
  11627.        }
  11628.      }
  11629.    }
  11630.  
  11631.    if (ep->mode == JES) {
  11632.      if (allocate_sysout(ep,&sys)) {
  11633.        sprintf(ggexdsn,"dd:%s",ep->ddname);
  11634.      }
  11635.      else *ggexdsn = '\0';
  11636.    }
  11637.  
  11638.    if (ep->mode == PDS) {
  11639.      xfp = DUMMY_FILE_POINTER;
  11640.      break;
  11641.    }
  11642.  
  11643.    if (*ggexdsn) {
  11644.  
  11645.      if (ep->mode == JES) {
  11646.        xfp = OPEN_SYSOUT_FILE(ggexdsn);
  11647.      }
  11648.      else {
  11649.        xfp = OPEN_TEXT_FILE_FOR_WRITE_OR_APPEND(ggexdsn,ep->appending);
  11650.      }
  11651.  
  11652.      if (!xfp) {
  11653. #ifdef SNSTCPIP
  11654.        fprintf(stderr,"Open failure: errno=%d\n",GET_ERRNO);
  11655. #else
  11656.        fprintf(stderr,"Open failure: errno=%d\n",errno);
  11657. #endif
  11658.        perror(ggexdsn);
  11659.        ERR2("Cannot open data set %s.", ep->dsname);
  11660.      }
  11661.    }
  11662.  }
  11663.  
  11664.  ISPF("REMPOP");
  11665.  
  11666.  return xfp;
  11667.  
  11668. }
  11669.  
  11670. ./ ADD NAME=GGGETM
  11671.  
  11672.  /********************************************************************/
  11673.  /*                                                                  */
  11674.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  11675.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  11676.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  11677.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  11678.  /*                                                                  */
  11679.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  11680.  /* including the implied warranties of merchantability and fitness, */
  11681.  /* are expressly denied.                                            */
  11682.  /*                                                                  */
  11683.  /* Provided this copyright notice is included, this software may    */
  11684.  /* be freely distributed and not offered for sale.                  */
  11685.  /*                                                                  */
  11686.  /* Changes or modifications may be made and used only by the maker  */
  11687.  /* of same, and not further distributed.  Such modifications should */
  11688.  /* be mailed to the author for consideration for addition to the    */
  11689.  /* software and incorporation in subsequent releases.               */
  11690.  /*                                                                  */
  11691.  /********************************************************************/
  11692.  
  11693. #pragma  csect(code,  "GG@GETM ")
  11694. #pragma  csect(static,"GG$GETM ")
  11695. #include "gg.h"
  11696.  
  11697. /****** Get memory. **************************************************/
  11698.  
  11699. void
  11700. GGgetm(gp,pointer,howmuch,whatfor)
  11701. RGGCB *gp;
  11702. char **pointer;
  11703. int    howmuch;
  11704. char  *whatfor;
  11705. {
  11706.  
  11707.  *pointer = (char *)malloc(howmuch);
  11708.  
  11709.  if (!*pointer) {
  11710.    fprintf(stderr,"GGgetm: Cannot obtain %d bytes of memory for %s\n",
  11711.                   howmuch,whatfor);
  11712.  }
  11713.  else if (gp && gp->debug_file) {
  11714.    fprintf(gp->debug_file,"GGgetm: got %d bytes of memory for %s\n",
  11715.                            howmuch,whatfor);
  11716.  }
  11717.  return;
  11718.  
  11719. }
  11720.  
  11721. ./ ADD NAME=GGGOFOR
  11722.  
  11723.  /********************************************************************/
  11724.  /*                                                                  */
  11725.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  11726.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  11727.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  11728.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  11729.  /*                                                                  */
  11730.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  11731.  /* including the implied warranties of merchantability and fitness, */
  11732.  /* are expressly denied.                                            */
  11733.  /*                                                                  */
  11734.  /* Provided this copyright notice is included, this software may    */
  11735.  /* be freely distributed and not offered for sale.                  */
  11736.  /*                                                                  */
  11737.  /* Changes or modifications may be made and used only by the maker  */
  11738.  /* of same, and not further distributed.  Such modifications should */
  11739.  /* be mailed to the author for consideration for addition to the    */
  11740.  /* software and incorporation in subsequent releases.               */
  11741.  /*                                                                  */
  11742.  /********************************************************************/
  11743.  
  11744. #pragma  csect(code,  "GG@GOFOR")
  11745. #pragma  csect(static,"GG$GOFOR")
  11746. #include "gg.h"
  11747.  
  11748. /********************************************************************/
  11749.  
  11750. static Bool
  11751. connect_and_get_data_from_gopher_server(gp,sp,ip,crmode)
  11752. RGGCB     *gp;
  11753. RCONN     *sp;
  11754. RINFO     *ip;
  11755. IOMODE     crmode;
  11756. {
  11757.  char     *lp;
  11758.  Bool      got_some;
  11759.  
  11760.  strcpy(gp->ggserver,ip->host);     /* Specify server to connect to */
  11761.  strcpy(gp->gopher_command,ip->path);   /* Specify command to issue */
  11762.  gp->ginfo = ip;
  11763.  sp->receiving_text = FALSE;
  11764.  
  11765.  if (!GGconn(gp,sp)) return FALSE;   /* Connect to gopher server */
  11766.  GOPHERSEND(gp,sp);                  /* Send socket command */
  11767.  GGclrtx(gp,ip);                    /* Clear text */
  11768.  
  11769.  sp->receiving_text = TRUE;
  11770.  got_some = FALSE;
  11771.  while (GGgsrvl(gp,sp,&lp,crmode)) {  /* Get server line */
  11772.    if (!lp) break;
  11773.    got_some = TRUE;
  11774.    (void)GGouttx(gp,lp,ip,            /* Output text line */
  11775.                  crmode == RBIN ? sp->nbytes : NO_VALUE);
  11776.  }
  11777.  
  11778.  if (!got_some) {
  11779.    WARN2("No data available from server %s.\n",gp->ggserver);
  11780.    return FALSE;
  11781.  }
  11782.  
  11783.  return TRUE;
  11784. }
  11785.  
  11786. /****** Gopher it. ***************************************************/
  11787.  
  11788. Bool
  11789. GGgofor(gp,ip,how)
  11790. RGGCB  *gp;
  11791. RINFO  *ip;
  11792. GOHOW   how;
  11793. {
  11794.  RCONN *sp = &gp->gopher_connection;
  11795.  Bool (*fun)(GGCB *, GOPHERINFO *, GOHOW);
  11796.  Bool   con;
  11797.  Bool   rc;
  11798.  IOMODE cr;
  11799.  char   savebook[63];
  11800.  
  11801.    /* (1) send initial path string to initial host
  11802.     * (2) get back data from host
  11803.     * (3) if it is a gopher directory, then do:
  11804.     *      - display "table" of items
  11805.     *      - for each item selected, call GGgofor recursively
  11806.     *     else browse the file data
  11807.     * (4) bye
  11808.     */
  11809.  
  11810.  if (gp->debug_mode) {
  11811.    fprintf(gp->debug_file,"GGgofor: type = %c\n",ip->type);
  11812.    fprintf(gp->debug_file,"GGgofor: port = %d\n",ip->port);
  11813.    fprintf(gp->debug_file,"GGgofor: path = %s\n",ip->path);
  11814.    fprintf(gp->debug_file,"GGgofor: host = %s\n",ip->host);
  11815.    fprintf(gp->debug_file,"GGgofor: desc = %s\n",ip->desc);
  11816.    fprintf(gp->debug_file,"GGgofor: bmds = %s\n",ip->bmds);
  11817.  }
  11818.  
  11819.  switch (ip->type) {
  11820.    case GOPHER_FILE:       fun = GGvtx;   con = TRUE;  cr = CRLF; break;
  11821.    case GOPHER_DIRECTORY:  fun = GGdir;   con = TRUE;  cr = CRLF; break;
  11822.    case GOPHER_TELNET:     fun = GGtnet;  con = FALSE; cr = CRLF; break;
  11823.    case GOPHER_TN3270:     fun = GGtnet;  con = FALSE; cr = CRLF; break;
  11824.    case GOPHER_WAIS:       fun = GGwais;  con = FALSE; cr = CRLF; break;
  11825.    case GOPHER_WHOIS:      fun = GGwhois; con = FALSE; cr = CRLF; break;
  11826.    case GOPHER_CSO:        fun = GGcso;   con = FALSE; cr = NOCR; break;
  11827.    case GOPHER_BOOKMANAGER:fun = GGbkmgr; con = TRUE;  cr = RBIN; break;
  11828.    case GOPHER_MAC_BINHEX:
  11829.    case GOPHER_DOS_BINARCH:
  11830.    case GOPHER_BINARY:     fun = GGbin;   con = TRUE;  cr = RBIN; break;
  11831.    case GOPHER_ERROR:      return TRUE;
  11832.    case GOPHER_COMMENT:    return TRUE;
  11833.    default:
  11834.         ERR2("Sorry, accessing an item of type %s is not supported",
  11835.              GGtype(ip->type));
  11836.         return FALSE;
  11837.  }
  11838.  
  11839.  if (con) {
  11840.    rc = connect_and_get_data_from_gopher_server(gp,sp,ip,cr);
  11841.  }
  11842.  
  11843.  /* Insure no connection is active once we do the real thing. */
  11844.  
  11845.  if (sp->connected_to_server) {
  11846.    (void)GGdisc(gp,sp);     /* Disconnect from gopher server */
  11847.  }
  11848.  
  11849.  if (!rc) return FALSE;     /* Fail if could not get data */
  11850.  
  11851.  strcpy(savebook,gp->current_bookmark_ds);
  11852.  if (EQUAL(ip->host, LOCAL_HOST_FROB)) {
  11853.    strncpy(gp->current_bookmark_ds,ip->path,sizeof(savebook));
  11854.  }
  11855.  else {
  11856.    strcpy(gp->current_bookmark_ds,"");
  11857.  }
  11858.  
  11859.  rc = (fun)(gp,ip,how);
  11860.  
  11861.  strcpy(gp->current_bookmark_ds,savebook);
  11862.  
  11863.  return rc;
  11864.  
  11865. }
  11866.  
  11867. ./ ADD NAME=GGGSRVL
  11868.  
  11869.  /********************************************************************/
  11870.  /*                                                                  */
  11871.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  11872.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  11873.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  11874.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  11875.  /*                                                                  */
  11876.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  11877.  /* including the implied warranties of merchantability and fitness, */
  11878.  /* are expressly denied.                                            */
  11879.  /*                                                                  */
  11880.  /* Provided this copyright notice is included, this software may    */
  11881.  /* be freely distributed and not offered for sale.                  */
  11882.  /*                                                                  */
  11883.  /* Changes or modifications may be made and used only by the maker  */
  11884.  /* of same, and not further distributed.  Such modifications should */
  11885.  /* be mailed to the author for consideration for addition to the    */
  11886.  /* software and incorporation in subsequent releases.               */
  11887.  /*                                                                  */
  11888.  /********************************************************************/
  11889.  
  11890. #pragma  csect(code,  "GG@GSRVL")
  11891. #pragma  csect(static,"GG$GSRVL")
  11892. #include "gg.h"
  11893.  
  11894. /****** Input one character from the server. *************************/
  11895.  
  11896. static int
  11897. socket_getchar(sp,crmode)
  11898. RCONN         *sp;
  11899. IOMODE         crmode;
  11900. {
  11901.  int           readrc;
  11902.  
  11903.  if (sp->buf_index == -1 || sp->buf_index >= sp->bytes_returned - 1) {
  11904.    sp->buf_index = -1;
  11905.    if (sp->dont_read) return SOCKET_NO_MORE;
  11906.    TCP_DEBUG_ON;
  11907.    readrc = read(sp->ns, sp->buf, READ_BYTES);
  11908.    TCP_DEBUG_OFF;
  11909.    if (readrc == -1) {
  11910.      sp->connection_broken = TRUE;
  11911.      return SOCKET_GETCHAR_ERROR;
  11912.    }
  11913.    else if (readrc == 0) {
  11914.      sp->connection_broken = FALSE;
  11915.      return SOCKET_READ_NOTHING;
  11916.    }
  11917.    else {
  11918.      if (crmode != RBIN) {
  11919.        ASCII_TO_EBCDIC(sp->buf,readrc);
  11920.      }
  11921.      sp->bytes_returned = readrc;
  11922.    }
  11923.  }
  11924.  return sp->buf[++sp->buf_index];
  11925. }
  11926.  
  11927. /****** Input one data line at a time from the server. ***************/
  11928.  
  11929. static RETVAL
  11930. socket_from_server(gp,sp,crmode)
  11931. RGGCB             *gp;
  11932. RCONN             *sp;
  11933. IOMODE             crmode;
  11934. {
  11935.  char             *s_buf       = sp->server_buf;
  11936.  int               s_bytes     = SERVER_BUF_MSGSIZE;
  11937.  int               s_buf_index = 0;
  11938.  int               previous_character = -1;
  11939.  int               character;
  11940.  
  11941.  /* Get characters from the server until LF is reached. */
  11942.  
  11943.  for (;;) {
  11944.    sp->nbytes = s_buf_index;
  11945.    if (crmode == RBIN && s_buf_index >= s_bytes) break;
  11946.    character = socket_getchar(sp,crmode);
  11947.    if (character == LINE_FEED && crmode != RBIN) break;
  11948.    if (character == SOCKET_GETCHAR_ERROR)  return SERVER_READ_ERROR;
  11949.    if (character == SOCKET_NO_MORE)        return SERVER_NO_MORE;
  11950.    if (character == SOCKET_READ_NOTHING)   return SERVER_READ_NOTHING;
  11951.    previous_character = character;
  11952.    if (s_buf_index >= s_bytes) {
  11953.      fprintf(stderr,
  11954.              "Error: More than %d bytes received without Line Feed.\n",
  11955.              s_bytes);
  11956.      if (gp && gp->debug_file) {
  11957.        GGdump(gp,"Data collected so far",sp->server_buf,s_bytes);
  11958.      }
  11959.      return SERVER_BUFFER_ERROR;
  11960.    }
  11961.    if (crmode != RBIN && character == '\0' && !sp->is_ftp) {
  11962.      fprintf(stderr,
  11963.    "Warning: null character found in server data, changed to blank\n");
  11964.      character = ' ';
  11965.    }
  11966.    s_buf[s_buf_index++] = (unsigned char)character;
  11967.  }
  11968.  s_buf[s_buf_index] = '\0';
  11969.  return SERVER_READ_OK;
  11970. }
  11971.  
  11972. /****** Get server line. *********************************************/
  11973.  
  11974. Bool
  11975. GGgsrvl(gp,sp,pointer,crmode)
  11976. RGGCB  *gp;
  11977. RCONN  *sp;
  11978. char  **pointer;
  11979. IOMODE  crmode;
  11980. {
  11981.  RRECV *R;
  11982.  char  *sbufp;
  11983.  char  *p;
  11984.  int    scan_count;
  11985.  Bool   something_to_print;
  11986.  RETVAL sfs;
  11987.  
  11988.  if (pointer) *pointer = NULL;
  11989.  
  11990.  /* If local mode, read from temporary file until EOF. */
  11991.  
  11992.  if (gp && (R=gp->recvp) && !sp->is_ftp) {
  11993.    if (!R->outfp) {
  11994.      CRIT1("Can't read data locally, non-socket not connected\n");
  11995.      return FALSE;
  11996.    }
  11997.    if (crmode == RBIN) {
  11998.      sp->nbytes =
  11999.        fread(sp->server_buf,sizeof(char),SERVER_BUF_MSGSIZE,R->outfp);
  12000.      if (ferror(R->outfp)) {
  12001.        CRIT1("Error reading local non-socket data\n");
  12002.        sp->time_to_go_home = TRUE;
  12003.        return FALSE;
  12004.      }
  12005.      if (sp->nbytes <= 0) return FALSE;
  12006.      if (pointer) *pointer = sp->server_buf;
  12007.      return TRUE;
  12008.    }
  12009.    else {
  12010.      fgets(sp->server_buf, SERVER_BUF_MSGSIZE, R->outfp);
  12011.      if (ferror(R->outfp)) {
  12012.        CRIT1("Error reading local non-socket data\n");
  12013.        sp->time_to_go_home = TRUE;
  12014.        return FALSE;
  12015.      }
  12016.      if ((p=strchr(sp->server_buf,'\n'))) *p = '\0';
  12017.      if (pointer) *pointer = sp->server_buf;
  12018.      if (feof(R->outfp)) return FALSE;
  12019.      return TRUE;
  12020.    }
  12021.  }
  12022.  
  12023.  if (sp->is_ftp) {
  12024.  
  12025.    sp->time_to_go_home = FALSE;
  12026.    sp->server_has_nothing = FALSE;
  12027.  
  12028.    switch (socket_from_server(gp,sp,crmode)) {
  12029.      case SERVER_READ_OK:      return TRUE;
  12030.      case SERVER_READ_NOTHING: if (crmode == RBIN) sp->dont_read = TRUE;
  12031.                                else sp->server_has_nothing = TRUE;
  12032.                                return TRUE;
  12033.      case SERVER_NO_MORE:      sp->server_has_nothing = TRUE;
  12034.                                return TRUE;
  12035.      case SERVER_READ_ERROR:   fprintf(stderr,
  12036.        "Lost server connection.  Failure reading data from server %s.",
  12037.                                        sp->server_hostname);
  12038.                                sp->time_to_go_home = TRUE;
  12039.                                return FALSE;
  12040.      case SERVER_BUFFER_ERROR: fprintf(stderr,
  12041.    "Read error.  No linefeed character found in data from server %s.",
  12042.                                     sp->server_hostname);
  12043.                                sp->time_to_go_home = TRUE;
  12044.                                return FALSE;
  12045.    }
  12046.  }
  12047.  
  12048.  if (!sp->receiving_text) return TRUE;
  12049.  if (sp->server_finished_replying) sp->dont_read = TRUE;
  12050.  
  12051.  sfs = socket_from_server(gp,sp,crmode);
  12052.  switch (sfs) {
  12053.    case SERVER_READ_OK:      break;
  12054.    case SERVER_READ_NOTHING: if (crmode == RBIN) sp->dont_read = TRUE;
  12055.                              else sp->time_to_go_home = TRUE;
  12056.                              break;
  12057.    case SERVER_READ_ERROR:   ERR2(
  12058.      "Lost server connection.  Failure reading data from server %s.",
  12059.                                   sp->server_hostname);
  12060.                              sp->time_to_go_home = TRUE;
  12061.                              break;
  12062.    case SERVER_BUFFER_ERROR: ERR2(
  12063.  "Read error.  No linefeed character found in data from server %s.",
  12064.                                   sp->server_hostname);
  12065.                              sp->time_to_go_home = TRUE;
  12066.                              break;
  12067.    case SERVER_NO_MORE:      sp->server_has_nothing = TRUE;
  12068.                              break;
  12069.  }
  12070.  
  12071.  if (sp->time_to_go_home) return FALSE;
  12072.  if (sp->dont_read && sp->server_has_nothing) return TRUE;
  12073.  
  12074.  something_to_print = TRUE;
  12075.  sbufp = sp->server_buf;
  12076.  
  12077.  if (sp->sending_text && crmode != RBIN) {
  12078.    if (*sbufp == '.') {
  12079.      switch (*(sbufp+1)) {
  12080.         case CARRIAGE_RETURN:
  12081.         case LINE_FEED:
  12082.         case '\0':
  12083.                   sp->server_finished_replying = TRUE;
  12084.                   something_to_print = FALSE;
  12085.                   break;
  12086.         case '.':
  12087.                   break;
  12088.         default:  if (gp) {
  12089.                    GGdump(gp,"Warning, bad period in line from server",
  12090.                              sbufp,strlen(sbufp));
  12091.                   }
  12092.                   break;
  12093.      }
  12094.    }
  12095.  }
  12096.  
  12097.  sp->sending_text = TRUE;
  12098.  
  12099.  if (something_to_print) {
  12100.    /* Last character of output buffer is a CR without LF. */
  12101.    if (crmode != RBIN) {
  12102.      p = sbufp + strlen(sbufp)-1;
  12103.      if (p >= sbufp) {
  12104.        if (*p == CARRIAGE_RETURN) *p = '\0';
  12105.        else if (crmode == CRLF) {
  12106.          /* Last character of output buffer had better be a LF. */
  12107.          if (gp && gp->debug_file) {
  12108.            fprintf(gp->debug_file,
  12109.    "Warning: No carriage return in data from server (%d bytes):\n%s\n",
  12110.                  strlen(sbufp), sbufp);
  12111.          }
  12112.          CRIT2(
  12113. "Carriage return expected but not seen in data from server %s.",
  12114.                sp->server_hostname);
  12115.        }
  12116.        *(p+1) = '\0';
  12117.        sp->nbytes = (p+1) - sbufp;
  12118.      }
  12119.    }
  12120.    if (pointer) *pointer = sbufp;
  12121.  }
  12122.  
  12123.  if (sp->time_to_go_home) return FALSE;
  12124.  else return TRUE;
  12125. }
  12126.  
  12127. ./ ADD NAME=GGIERR
  12128.  
  12129.  /********************************************************************/
  12130.  /*                                                                  */
  12131.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  12132.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  12133.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  12134.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  12135.  /*                                                                  */
  12136.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  12137.  /* including the implied warranties of merchantability and fitness, */
  12138.  /* are expressly denied.                                            */
  12139.  /*                                                                  */
  12140.  /* Provided this copyright notice is included, this software may    */
  12141.  /* be freely distributed and not offered for sale.                  */
  12142.  /*                                                                  */
  12143.  /* Changes or modifications may be made and used only by the maker  */
  12144.  /* of same, and not further distributed.  Such modifications should */
  12145.  /* be mailed to the author for consideration for addition to the    */
  12146.  /* software and incorporation in subsequent releases.               */
  12147.  /*                                                                  */
  12148.  /********************************************************************/
  12149.  
  12150. #pragma  csect(code,  "GG@IERR ")
  12151. #pragma  csect(static,"GG$IERR ")
  12152. #include "gg.h"
  12153.  
  12154. /****** ISPF error handler. ******************************************/
  12155.  
  12156. void
  12157. GGierr(gp)
  12158. RGGCB *gp;
  12159. {
  12160.  char  errbuf[] = "DISPLAY PANEL(ISPTERM)";
  12161.  int   errlen;
  12162.  
  12163.  errlen = strlen(errbuf);
  12164.  if (ISPEXEC(&errlen,errbuf) > 8) {
  12165.    fprintf(stderr,
  12166. "\n*** Severe ISPF error, cannot even display ISPTERM error panel.\n");
  12167.    fprintf(stderr,
  12168. "\n*** Return code from ISPF service is %d\n",gp->ispfrc);
  12169.    return;
  12170.  }
  12171. }
  12172.  
  12173. ./ ADD NAME=GGIGET
  12174.  
  12175.  /********************************************************************/
  12176.  /*                                                                  */
  12177.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  12178.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  12179.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  12180.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  12181.  /*                                                                  */
  12182.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  12183.  /* including the implied warranties of merchantability and fitness, */
  12184.  /* are expressly denied.                                            */
  12185.  /*                                                                  */
  12186.  /* Provided this copyright notice is included, this software may    */
  12187.  /* be freely distributed and not offered for sale.                  */
  12188.  /*                                                                  */
  12189.  /* Changes or modifications may be made and used only by the maker  */
  12190.  /* of same, and not further distributed.  Such modifications should */
  12191.  /* be mailed to the author for consideration for addition to the    */
  12192.  /* software and incorporation in subsequent releases.               */
  12193.  /*                                                                  */
  12194.  /********************************************************************/
  12195.  
  12196. #pragma  csect(code,  "GG@IGET ")
  12197. #pragma  csect(static,"GG$IGET ")
  12198. #include "gg.h"
  12199.  
  12200. /****** Retrieve the value of an ISPF variable into an integer. ******/
  12201.  
  12202. int
  12203. GGiget(gp,varname)
  12204. RGGCB *gp;
  12205. char  *varname;
  12206. {
  12207.  char  varbuf [16];
  12208.  int   vcopy_length = 16;
  12209.  
  12210.  if (!strchr(varname,' ')) {
  12211.    fprintf(stderr,"GGiget: no blank passed in variable name %s\n",
  12212.                   varname);
  12213.    return FALSE;
  12214.  }
  12215.  
  12216.  gp->ispfrc = ISPLINK("VCOPY",varname,&vcopy_length,varbuf,"MOVE");
  12217.  switch (gp->ispfrc) {
  12218.    case  0:
  12219.            varbuf[vcopy_length] = '\0';
  12220.            return atoi(varbuf);
  12221.    case  8:
  12222.            return 0;
  12223.    case 16:
  12224.            fprintf(stderr,
  12225.                    "Error: ISPF variable buffer too short to get %s\n",
  12226.                    varname);
  12227.            return 0;
  12228.    default:
  12229.            GGierr(gp);   /* handle ISPF error */
  12230.            return 0;
  12231.  }
  12232. }
  12233.  
  12234. ./ ADD NAME=GGINFO
  12235.  
  12236.  /********************************************************************/
  12237.  /*                                                                  */
  12238.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  12239.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  12240.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  12241.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  12242.  /*                                                                  */
  12243.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  12244.  /* including the implied warranties of merchantability and fitness, */
  12245.  /* are expressly denied.                                            */
  12246.  /*                                                                  */
  12247.  /* Provided this copyright notice is included, this software may    */
  12248.  /* be freely distributed and not offered for sale.                  */
  12249.  /*                                                                  */
  12250.  /* Changes or modifications may be made and used only by the maker  */
  12251.  /* of same, and not further distributed.  Such modifications should */
  12252.  /* be mailed to the author for consideration for addition to the    */
  12253.  /* software and incorporation in subsequent releases.               */
  12254.  /*                                                                  */
  12255.  /********************************************************************/
  12256.  
  12257. #pragma  csect(code,  "GG@INFO ")
  12258. #pragma  csect(static,"GG$INFO ")
  12259. #include "gg.h"
  12260.  
  12261. /****** Gopher it. ***************************************************/
  12262.  
  12263. Bool
  12264. GGinfo(gp,ip)
  12265. RGGCB *gp;
  12266. RINFO *ip;
  12267. {
  12268.  char  buf [513];
  12269.  
  12270.  if (!ip) {
  12271.    ERR1("Info is not available - this is not a Gopher item.");
  12272.    return FALSE;
  12273.  }
  12274.  
  12275.  GGclrtx(gp,NULL);
  12276.  
  12277.  sprintf(buf,"");                  GGouttx(gp,buf,NULL,NO_VALUE);
  12278.  sprintf(buf,"Type=%c%c",
  12279.               ip->type,ip->plus);  GGouttx(gp,buf,NULL,NO_VALUE);
  12280.  sprintf(buf,"Name=%s",ip->desc);  GGouttx(gp,buf,NULL,NO_VALUE);
  12281.  sprintf(buf,"Path=%s",ip->path);  GGouttx(gp,buf,NULL,NO_VALUE);
  12282.  sprintf(buf,"Host=%s",ip->host);  GGouttx(gp,buf,NULL,NO_VALUE);
  12283.  sprintf(buf,"Port=%d",ip->port);  GGouttx(gp,buf,NULL,NO_VALUE);
  12284.  sprintf(buf,"End");               GGouttx(gp,buf,NULL,NO_VALUE);
  12285.  
  12286.  return TRUE;
  12287. }
  12288.  
  12289. ./ ADD NAME=GGISPF
  12290.  
  12291.  /********************************************************************/
  12292.  /*                                                                  */
  12293.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  12294.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  12295.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  12296.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  12297.  /*                                                                  */
  12298.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  12299.  /* including the implied warranties of merchantability and fitness, */
  12300.  /* are expressly denied.                                            */
  12301.  /*                                                                  */
  12302.  /* Provided this copyright notice is included, this software may    */
  12303.  /* be freely distributed and not offered for sale.                  */
  12304.  /*                                                                  */
  12305.  /* Changes or modifications may be made and used only by the maker  */
  12306.  /* of same, and not further distributed.  Such modifications should */
  12307.  /* be mailed to the author for consideration for addition to the    */
  12308.  /* software and incorporation in subsequent releases.               */
  12309.  /*                                                                  */
  12310.  /********************************************************************/
  12311.  
  12312. #pragma  csect(code,  "GG@ISPF ")
  12313. #pragma  csect(static,"GG$ISPF ")
  12314. #include "gg.h"
  12315.  
  12316. /****** Call ISPF service. *******************************************/
  12317.  
  12318. Bool
  12319. GGispf(gp,ispfbuf)
  12320. RGGCB *gp;
  12321. char  *ispfbuf;
  12322. {
  12323.  int   ispflen = strlen(ispfbuf);
  12324.  
  12325.  if (!gp) return TRUE;
  12326.  
  12327. #ifndef ISPFV2
  12328.  if (gp->test_mode) {
  12329. #endif
  12330.    if (ispflen >= 6 && (!memcmp(ispfbuf,"ADDPOP",6) ||
  12331.                         !memcmp(ispfbuf,"REMPOP",6))) {
  12332.      gp->ispfrc = 0;
  12333.      return TRUE;
  12334.    }
  12335. #ifndef ISPFV2
  12336.  }
  12337. #endif
  12338.  
  12339.  gp->ispfrc = ISPEXEC(&ispflen,ispfbuf);
  12340.  if (gp->ispfrc > 8) {
  12341.  
  12342.    /* Ignore ADDPOP and REMPOP errors, especially if they are due to
  12343.       ISPF V3 not being active. */
  12344.  
  12345.    if (gp->ispfrc == 20 && !gp->debug_mode && ispflen >= 6 &&
  12346.        (!memcmp(ispfbuf,"ADDPOP",6) ||
  12347.         !memcmp(ispfbuf,"REMPOP",6))) return TRUE;
  12348.  
  12349.    GGierr(gp);             /* handle ISPF error */
  12350.    return FALSE;
  12351.  }
  12352.  return TRUE;
  12353. }
  12354.  
  12355. ./ ADD NAME=GGIVGET
  12356.  
  12357.  /********************************************************************/
  12358.  /*                                                                  */
  12359.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  12360.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  12361.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  12362.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  12363.  /*                                                                  */
  12364.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  12365.  /* including the implied warranties of merchantability and fitness, */
  12366.  /* are expressly denied.                                            */
  12367.  /*                                                                  */
  12368.  /* Provided this copyright notice is included, this software may    */
  12369.  /* be freely distributed and not offered for sale.                  */
  12370.  /*                                                                  */
  12371.  /* Changes or modifications may be made and used only by the maker  */
  12372.  /* of same, and not further distributed.  Such modifications should */
  12373.  /* be mailed to the author for consideration for addition to the    */
  12374.  /* software and incorporation in subsequent releases.               */
  12375.  /*                                                                  */
  12376.  /********************************************************************/
  12377.  
  12378. #pragma  csect(code,  "GG@IVGET")
  12379. #pragma  csect(static,"GG$IVGET")
  12380. #include "gg.h"
  12381.  
  12382. /****** Retrieve the value of an ISPF variable. **********************/
  12383.  
  12384. Bool
  12385. GGivget(gp,varname,varbuf,varbuflen)
  12386. RGGCB  *gp;
  12387. char   *varname;
  12388. char   *varbuf;
  12389. int     varbuflen;
  12390. {
  12391.  int    vcopy_length;
  12392.  
  12393.  if (!strchr(varname,' ')) {
  12394.    fprintf(stderr,"GGivget: no blank passed in variable name %s\n",
  12395.                   varname);
  12396.    return FALSE;
  12397.  }
  12398.  
  12399.  /*
  12400.   * If varbuflen is negative, that means that the value is not to be
  12401.   * treated as a C string, and the null character is not to be
  12402.   * appended to the resulting value.  This is used for hex values
  12403.   * (like addresses) that are stored in ISPF table row variables.
  12404.   */
  12405.  
  12406.  if (varbuflen < 0)  vcopy_length = -varbuflen;
  12407.  else vcopy_length = varbuflen;
  12408.  
  12409.  /* Note that on entry, vcopy_length is an integer that contains
  12410.   * the length of the buffer.  On return it is updated to the length
  12411.   * of the value returned.  Since we have to stick a null character
  12412.   * on the end of it for C, the actual buffer passed must be at least
  12413.   * one character longer than the length as defined to ISPF.
  12414.   */
  12415.  
  12416.  gp->ispfrc = ISPLINK("VCOPY",varname,&vcopy_length,varbuf,"MOVE");
  12417.  switch (gp->ispfrc) {
  12418.    case  0:
  12419.            if (varbuflen >= 0)
  12420.               varbuf[vcopy_length] = '\0';
  12421.            return TRUE;
  12422.    case  8:
  12423.            strcpy(varbuf,"");
  12424.            return TRUE;
  12425.    case 16:
  12426.            fprintf(stderr,
  12427.                    "Error: ISPF variable buffer too short to get %s\n",
  12428.                    varname);
  12429.            return FALSE;
  12430.    default:
  12431.            GGierr(gp);   /* handle ISPF error */
  12432.            return FALSE;
  12433.  }
  12434. }
  12435.  
  12436. ./ ADD NAME=GGIVPUT
  12437.  
  12438.  /********************************************************************/
  12439.  /*                                                                  */
  12440.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  12441.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  12442.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  12443.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  12444.  /*                                                                  */
  12445.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  12446.  /* including the implied warranties of merchantability and fitness, */
  12447.  /* are expressly denied.                                            */
  12448.  /*                                                                  */
  12449.  /* Provided this copyright notice is included, this software may    */
  12450.  /* be freely distributed and not offered for sale.                  */
  12451.  /*                                                                  */
  12452.  /* Changes or modifications may be made and used only by the maker  */
  12453.  /* of same, and not further distributed.  Such modifications should */
  12454.  /* be mailed to the author for consideration for addition to the    */
  12455.  /* software and incorporation in subsequent releases.               */
  12456.  /*                                                                  */
  12457.  /********************************************************************/
  12458.  
  12459. #pragma  csect(code,  "GG@IVPUT")
  12460. #pragma  csect(static,"GG$IVPUT")
  12461. #include "gg.h"
  12462.  
  12463. /****** Set the value of an ISPF variable. ***************************/
  12464.  
  12465. Bool
  12466. GGivput(gp,varname,varbuf,varlen)
  12467. RGGCB  *gp;
  12468. char   *varname;
  12469. char   *varbuf;
  12470. int     varlen;
  12471. {
  12472.  int    vreplace_length = (varlen < 0 ? strlen(varbuf) : varlen);
  12473.  
  12474.  gp->ispfrc = ISPLINK("VREPLACE",varname,&vreplace_length,varbuf);
  12475.  switch (gp->ispfrc) {
  12476.    case  0:
  12477.            return TRUE;
  12478.    case 16:
  12479.            fprintf(stderr,
  12480.                    "Error: ISPF variable buffer too short to put %s\n",
  12481.                    varname);
  12482.            return FALSE;
  12483.    default:
  12484.            GGierr(gp);   /* handle ISPF error */
  12485.            return FALSE;
  12486.  }
  12487. }
  12488.  
  12489. ./ ADD NAME=GGMENU
  12490.  
  12491.  /********************************************************************/
  12492.  /*                                                                  */
  12493.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  12494.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  12495.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  12496.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  12497.  /*                                                                  */
  12498.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  12499.  /* including the implied warranties of merchantability and fitness, */
  12500.  /* are expressly denied.                                            */
  12501.  /*                                                                  */
  12502.  /* Provided this copyright notice is included, this software may    */
  12503.  /* be freely distributed and not offered for sale.                  */
  12504.  /*                                                                  */
  12505.  /* Changes or modifications may be made and used only by the maker  */
  12506.  /* of same, and not further distributed.  Such modifications should */
  12507.  /* be mailed to the author for consideration for addition to the    */
  12508.  /* software and incorporation in subsequent releases.               */
  12509.  /*                                                                  */
  12510.  /********************************************************************/
  12511.  
  12512. #pragma  csect(code,  "GG@MENU ")
  12513. #pragma  csect(static,"GG$MENU ")
  12514. #include "gg.h"
  12515.  
  12516. /****** Display Gopher menu in data set. *****************************/
  12517.  
  12518. Bool
  12519. GGmenu(gp,pp)
  12520. RGGCB *gp;
  12521. char  *pp;
  12522. {
  12523.  GOPHERINFO   *ip;
  12524.  GOPHERINFO   *saveip;
  12525.  char         *cp;
  12526.  Bool          rc;
  12527.  char          zprefix    [9];
  12528.  char          temp     [129];
  12529.  char          savebook  [63];
  12530.  
  12531.  if (!*pp) {
  12532.    ERR1("You must supply a data set name for a Gopher menu.");
  12533.    return FALSE;
  12534.  }
  12535.  
  12536.  if (strlen(pp) >= sizeof(temp)) {
  12537.    ERR1("Gopher menu name too long");
  12538.    return FALSE;
  12539.  }
  12540.  
  12541.  GETMAIN(ip, struct gopherinfo, 1, "menu gopherinfo struct");
  12542.  if (!ip) {
  12543.    ERR2("Not enough memory to load Gopher menu %s",pp);
  12544.    return FALSE;
  12545.  }
  12546.  
  12547.  CLEAR(ip);
  12548.  
  12549.  copy_uppercase(temp,pp);
  12550.  
  12551.  if (temp[0] == '\'') {
  12552.    strcpy(ip->path, temp+1);
  12553.    cp = &ip->path[strlen(ip->path)-1];
  12554.    if (*cp == '\'') *cp = '\0';
  12555.  }
  12556.  else {
  12557.    VGET("ZPREFIX ",zprefix);
  12558.    if (!*zprefix) sprintf(ip->path,"'%s'",pp);
  12559.    else sprintf(ip->path,"%s.%s",zprefix,pp);
  12560.  }
  12561.  
  12562.  ip->type  = GOPHER_MENU;
  12563.  sprintf(ip->desc,"User menu %s",ip->path);
  12564.  strcpy (ip->host, "-");
  12565.  ip->port  = SERV_TCP_PORT;
  12566.  saveip    = gp->ginfo;
  12567.  gp->ginfo = ip;
  12568.  strcpy(savebook,gp->current_bookmark_ds);
  12569.  strncpy(gp->current_bookmark_ds,ip->path,sizeof(savebook));
  12570.  
  12571.  rc = GGgofor(gp,ip,AS_NORMAL);
  12572.  
  12573.  gp->ginfo = saveip;
  12574.  strcpy(gp->current_bookmark_ds,savebook);
  12575.  
  12576.  FREEMAIN(ip,"menu gopherinfo struct");
  12577.  
  12578.  return rc;
  12579. }
  12580.  
  12581. ./ ADD NAME=GGMTFER
  12582.  
  12583.  /********************************************************************/
  12584.  /*                                                                  */
  12585.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  12586.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  12587.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  12588.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  12589.  /*                                                                  */
  12590.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  12591.  /* including the implied warranties of merchantability and fitness, */
  12592.  /* are expressly denied.                                            */
  12593.  /*                                                                  */
  12594.  /* Provided this copyright notice is included, this software may    */
  12595.  /* be freely distributed and not offered for sale.                  */
  12596.  /*                                                                  */
  12597.  /* Changes or modifications may be made and used only by the maker  */
  12598.  /* of same, and not further distributed.  Such modifications should */
  12599.  /* be mailed to the author for consideration for addition to the    */
  12600.  /* software and incorporation in subsequent releases.               */
  12601.  /*                                                                  */
  12602.  /********************************************************************/
  12603.  
  12604. #pragma  csect(code,  "GG@MTFER")
  12605. #pragma  csect(static,"GG$MTFER")
  12606. #include "gg.h"
  12607.  
  12608. /*********************************************************************/
  12609.  
  12610. void
  12611. GGmtfer(
  12612.         int     rc,
  12613.         char   *kind)
  12614. {
  12615.  char    *ermsg;
  12616.  
  12617.  switch (rc) {
  12618.    case MTF_OK:
  12619.         ermsg = NULL;
  12620.         break;
  12621.    case EINACTIVE:
  12622.         ermsg = "MTF is inactive";
  12623.         break;
  12624.    case ESUBCALL:
  12625.         ermsg = "The MTF call was issued from a subtask";
  12626.         break;
  12627.    case EWRONGOS:
  12628.         ermsg = "MTF is not supported under CMS, IMS, CICS, or DB2";
  12629.         break;
  12630.    case EACTIVE:
  12631.         ermsg = "MTF has already been initialized and is active";
  12632.         break;
  12633.    case ENAME2LNG:
  12634.         ermsg = "The parallel module name is longer than 8 characters";
  12635.         break;
  12636.    case ETASKNUM:
  12637.         ermsg = "The number of tasks specified is invalid";
  12638.         break;
  12639.    case ENOMEM:
  12640.         ermsg = "Insufficient storage for MTF internal areas";
  12641.         break;
  12642.    case EMODFIND:
  12643.         ermsg = "The parallel load module was not found";
  12644.         break;
  12645.    case EMODREAD:
  12646.         ermsg = "The parallel load module was not sucessfully read";
  12647.         break;
  12648.    case EMODFMT:
  12649.         ermsg = "The parallel load module format is invalid";
  12650.         break;
  12651.    case EAUTOALC:
  12652.         ermsg = "Automatic allocation of standard stream DD failed";
  12653.         break;
  12654.    case ETASKFAIL:
  12655.         ermsg = "The attempt to attach task(s) has failed";
  12656.         break;
  12657.    case ETASKABND:
  12658.         ermsg = "One or more subtasks have abnormally terminated";
  12659.         break;
  12660.    case EBADLNKG:
  12661.         ermsg = "TSCHED has been invoked via invalid linkage";
  12662.         break;
  12663.    case ETASKID:
  12664.         ermsg = "The task ID specified is not valid";
  12665.         break;
  12666.    case EENTRY:
  12667.         ermsg = "The parallel function was not in the parallel module";
  12668.         break;
  12669.    default:
  12670.         ermsg = "Unknown MTF error";
  12671.         break;
  12672.  }
  12673.  
  12674.  if (ermsg) {
  12675.    fprintf(stderr,"GGserve: %s error code %d:\n %s\n", kind, rc, ermsg);
  12676.  }
  12677.  
  12678.  return;
  12679.  
  12680. }
  12681.  
  12682. ./ ADD NAME=GGOUTS
  12683.  
  12684.  /********************************************************************/
  12685.  /*                                                                  */
  12686.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  12687.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  12688.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  12689.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  12690.  /*                                                                  */
  12691.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  12692.  /* including the implied warranties of merchantability and fitness, */
  12693.  /* are expressly denied.                                            */
  12694.  /*                                                                  */
  12695.  /* Provided this copyright notice is included, this software may    */
  12696.  /* be freely distributed and not offered for sale.                  */
  12697.  /*                                                                  */
  12698.  /* Changes or modifications may be made and used only by the maker  */
  12699.  /* of same, and not further distributed.  Such modifications should */
  12700.  /* be mailed to the author for consideration for addition to the    */
  12701.  /* software and incorporation in subsequent releases.               */
  12702.  /*                                                                  */
  12703.  /********************************************************************/
  12704.  
  12705. #pragma  csect(code,  "GG@OUTS")
  12706. #pragma  csect(static,"GG$OUTS")
  12707.  
  12708. #include "gg.h"
  12709.  
  12710. /*
  12711.  * This is a Gopher server routine that outputs data to a socket.
  12712.  * If the "socket" is actually a file pointer, then output is
  12713.  * written to the file pointer.
  12714.  *
  12715.  */
  12716.  
  12717. /*=================================================================*/
  12718.  
  12719. Bool
  12720. GGouts(RRECV *R,
  12721.        char  *text,
  12722.        int    outlen)
  12723. {
  12724.  char        *outp;
  12725.  int          len;
  12726.  int          reallen;
  12727.  Bool         rc;
  12728.  Bool         binary;
  12729.  char         outbuf [515];  /* hold an output character string */
  12730.  
  12731.  switch (R->pathtype) {
  12732.    case GOPHER_MAC_BINHEX:
  12733.    case GOPHER_DOS_BINARCH:
  12734.    case GOPHER_BINARY:   binary = TRUE;   break;
  12735.    default:              binary = FALSE;  break;
  12736.  }
  12737.  
  12738.  if (outlen == NO_VALUE) outlen = text ? strlen(text) : 0;
  12739.  else if (outlen == OUT_PLUS) {
  12740.    outlen = text ? strlen(text) : 0;
  12741.    binary = FALSE;
  12742.    if (!R->outfp)
  12743.       fprintf(stderr,"GGouts: %*.*s\n", outlen, outlen, text);
  12744.  }
  12745.  else binary = TRUE;
  12746.  
  12747.  if (R->outfp) {             /* if using non-socket interface */
  12748.    if (text) {
  12749.      if (fwrite(text, sizeof(char), outlen, R->outfp) < 0) {
  12750.        fprintf(stderr,"Error writing to output file\n");
  12751.        return FALSE;
  12752.      }
  12753.      if (!binary) {
  12754.        if (fputc('\n',R->outfp) < 0) {
  12755.          fprintf(stderr,"Error writing to output file\n");
  12756.          return FALSE;
  12757.        }
  12758.      }
  12759.    }
  12760.    return TRUE;
  12761.  }
  12762.  
  12763.  if (binary) {
  12764.    if (!text) {
  12765.      outp = "";
  12766.      len = 0;
  12767.    }
  12768.    else {
  12769.      outp = text;
  12770.      len = outlen;
  12771.    }
  12772.    reallen = len;
  12773.  }
  12774.  else {
  12775.    outp = outbuf;
  12776.    if (!text) {
  12777.      outbuf[0] = '.';
  12778.      len = 1;
  12779.    }
  12780.    else {
  12781.      len = strlen(text);
  12782.      if (len >= sizeof(outbuf)-3) len = sizeof(outbuf)-3;
  12783.      if (text[0] == '.') {
  12784.        outbuf[0] = '.';
  12785.        memcpy(outbuf+1,text,len);
  12786.        len++;
  12787.      }
  12788.      else {
  12789.        memcpy(outbuf,text,len);
  12790.      }
  12791.    }
  12792.    outbuf[len  ] = CARRIAGE_RETURN;
  12793.    outbuf[len+1] = LINE_FEED;
  12794.    outbuf[len+2] = '\0';
  12795.    reallen = len + 2;
  12796.  
  12797.    EBCDIC_TO_ASCII(outbuf,reallen);
  12798.  
  12799.  }
  12800.  
  12801.  rc = TRUE;
  12802.  
  12803.  if (R->outlen + reallen > sizeof(R->sockbuf)) {
  12804.  
  12805.    if (write(R->sockfd,R->sockbuf,R->outlen) < 0) {
  12806.      REPORT_TCP_ERROR("SEND");
  12807.      rc = FALSE;
  12808.    }
  12809.    R->outlen = 0;
  12810.  }
  12811.  
  12812.  memcpy(R->sockbuf + R->outlen, outp, reallen);
  12813.  R->outlen += reallen;
  12814.  
  12815.  if (!text) {  /* flush socket */
  12816.    if (write(R->sockfd,R->sockbuf,R->outlen) < 0) {
  12817.      REPORT_TCP_ERROR("SEND");
  12818.      rc = FALSE;
  12819.    }
  12820.  }
  12821.  return rc;
  12822. }
  12823.  
  12824. ./ ADD NAME=GGOUTTX
  12825.  
  12826.  /********************************************************************/
  12827.  /*                                                                  */
  12828.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  12829.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  12830.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  12831.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  12832.  /*                                                                  */
  12833.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  12834.  /* including the implied warranties of merchantability and fitness, */
  12835.  /* are expressly denied.                                            */
  12836.  /*                                                                  */
  12837.  /* Provided this copyright notice is included, this software may    */
  12838.  /* be freely distributed and not offered for sale.                  */
  12839.  /*                                                                  */
  12840.  /* Changes or modifications may be made and used only by the maker  */
  12841.  /* of same, and not further distributed.  Such modifications should */
  12842.  /* be mailed to the author for consideration for addition to the    */
  12843.  /* software and incorporation in subsequent releases.               */
  12844.  /*                                                                  */
  12845.  /********************************************************************/
  12846.  
  12847. #pragma  csect(code,  "GG@OUTTX")
  12848. #pragma  csect(static,"GG$OUTTX")
  12849. #include "gg.h"
  12850.  
  12851. /****** Output a line of text retrieved from the server. *************/
  12852.  
  12853. TEXTLINE *
  12854. GGouttx(gp,line,ip,len)
  12855. RGGCB     *gp;
  12856. char      *line;
  12857. RINFO     *ip;
  12858. int        len;
  12859. {
  12860.  TEXTHDR  *thp;
  12861.  TEXTLINE *tp;
  12862.  short     line_length;
  12863.  short     total_text_length;
  12864.  short     tab_expansion_length;
  12865.  Bool      tabs_present;
  12866.  char     *p;
  12867.  char     *q;
  12868.  char     *t;
  12869.  int       e;
  12870.  int       u;
  12871.  
  12872.  static char tab_expansion_buffer[8*TEXT_BYTES];
  12873.  
  12874.  thp = (ip ? &ip->thdr : &gp->thdr);
  12875.  
  12876.  /* If line starts with double period, make it a single period. */
  12877.  
  12878.  if (len != NO_VALUE) {
  12879.   line_length = len;
  12880.   tabs_present = FALSE;
  12881.   total_text_length = line_length + 1;
  12882.  }
  12883.  else {
  12884.  
  12885.    if (ip && !memcmp(line,"..",2)) line++;
  12886.  
  12887.    /* Add this line to the current queue of server text lines. */
  12888.    /* First, expand tabs in the line. */
  12889.  
  12890.    line_length = strlen(line);
  12891.    t = strchr(line,'\t');
  12892.    if (!t) {
  12893.      tabs_present = FALSE;
  12894.      total_text_length = line_length + 1;
  12895.    }
  12896.    else {
  12897.      tabs_present = TRUE;
  12898.      p = line;
  12899.      q = line + line_length;
  12900.      e = 0;
  12901.      memset(tab_expansion_buffer,' ',sizeof(tab_expansion_buffer));
  12902.      for (;;) {
  12903.        u = t - p;
  12904.        if (u > 0) {
  12905.          memcpy(tab_expansion_buffer+e,p,u);
  12906.          e += u;
  12907.        }
  12908.        if (t == q) break;
  12909.        e = e / 8 * 8 + 8;
  12910.        p = t+1;
  12911.        t = strchr(p,'\t');
  12912.        if (!t) t = q;
  12913.      }
  12914.      tab_expansion_length = e;
  12915.      tab_expansion_buffer[tab_expansion_length] = '\0';
  12916.      total_text_length = line_length + tab_expansion_length + 1;
  12917.    }
  12918.  }
  12919.  
  12920.  GETMAIN(tp, char, offsetof(struct textline, text) + total_text_length,
  12921.                    "text line");
  12922.  
  12923.  if (!tp) {
  12924.    ERR1("There is not enough virtual storage to process server text.");
  12925.    return NULL;
  12926.  }
  12927.  
  12928.  tp->next = NULL;
  12929.  tp->text_length = line_length;
  12930.  memcpy(tp->text,line,line_length);
  12931.  tp->text[line_length] = '\0';
  12932.  if (tabs_present) {
  12933.    tp->tab_expanded_text_length = tab_expansion_length;
  12934.    tp->tab_expanded_text = tp->text + line_length;
  12935.    strcpy(tp->tab_expanded_text,tab_expansion_buffer);
  12936.  }
  12937.  else {
  12938.    tp->tab_expanded_text_length = line_length;
  12939.    tp->tab_expanded_text = tp->text;
  12940.  }
  12941.  
  12942.  if (!thp->last_text_line) {
  12943.    thp->first_text_line   = tp;
  12944.    thp->text_body_line    = tp;
  12945.    thp->current_text_line = tp;
  12946.  }
  12947.  else thp->last_text_line->next = tp;
  12948.  
  12949.  thp->last_text_line = tp;
  12950.  thp->text_line_count++;
  12951.  
  12952.  if (thp->text_max_length < tp->text_length)
  12953.      thp->text_max_length = tp->text_length;
  12954.  if (thp->text_max_tab_expanded_length < tp->tab_expanded_text_length)
  12955.      thp->text_max_tab_expanded_length = tp->tab_expanded_text_length;
  12956.  
  12957.  return tp;
  12958.  
  12959. }
  12960.  
  12961. ./ ADD NAME=GGPMSG
  12962.  
  12963.  /********************************************************************/
  12964.  /*                                                                  */
  12965.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  12966.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  12967.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  12968.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  12969.  /*                                                                  */
  12970.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  12971.  /* including the implied warranties of merchantability and fitness, */
  12972.  /* are expressly denied.                                            */
  12973.  /*                                                                  */
  12974.  /* Provided this copyright notice is included, this software may    */
  12975.  /* be freely distributed and not offered for sale.                  */
  12976.  /*                                                                  */
  12977.  /* Changes or modifications may be made and used only by the maker  */
  12978.  /* of same, and not further distributed.  Such modifications should */
  12979.  /* be mailed to the author for consideration for addition to the    */
  12980.  /* software and incorporation in subsequent releases.               */
  12981.  /*                                                                  */
  12982.  /********************************************************************/
  12983.  
  12984. #define  SUPPRESS_V_DECLARATION
  12985. #pragma  csect(code,  "GG@PMSG ")
  12986. #pragma  csect(static,"GG$PMSG ")
  12987. #include "gg.h"
  12988.  
  12989. /****** Set an ISPF message, or write to SYSOUT if batch mode. *******/
  12990.  
  12991. void
  12992. GGpmsg(gp,msgtype,msghelp,msgformat) /* also ... for sprintf args */
  12993. RGGCB *gp;
  12994. int    msgtype;
  12995. char  *msghelp;
  12996. char  *msgformat;
  12997. {
  12998.  va_list     argp;
  12999.  char       *cp;
  13000.  char        zerrsm    [25];
  13001.  char        zerrhm     [9];
  13002.  char        zerralrm   [4];
  13003.  char        zerrlm   [ZERRLM_SIZE];
  13004.  char        buf      [257];
  13005.  
  13006.  va_start(argp,msgformat);
  13007.  vsprintf(buf,msgformat,argp);
  13008.  va_end(argp);
  13009.  
  13010.  cp = strchr(buf,';');
  13011.  if (cp) {
  13012.   *cp = '\0';
  13013.   strncpy(zerrsm,buf, sizeof(zerrsm));
  13014.   strncpy(zerrlm,cp+1,sizeof(zerrlm));
  13015.  }
  13016.  else {
  13017.   strcpy(zerrsm,"");
  13018.   strncpy(zerrlm,buf,sizeof(zerrlm));
  13019.  }
  13020.  
  13021.  zerrsm[sizeof(zerrsm)-1] = '\0';
  13022.  zerrlm[sizeof(zerrlm)-1] = '\0';
  13023.  
  13024.  if (msghelp) strcpy(zerrhm, msghelp);
  13025.  else         strcpy(zerrhm, "*"    );
  13026.  
  13027.  switch (msgtype) {
  13028.    case NOTIFY_MSG:    strcpy(zerralrm,"NO "); break;
  13029.    case WARNING_MSG:
  13030.    case CRITICAL_MSG:
  13031.    default:            strcpy(zerralrm,"YES"); break;
  13032.  }
  13033.  
  13034.  VPUT("ZERRSM ",  zerrsm);
  13035.  VPUT("ZERRLM ",  zerrlm);
  13036.  VPUT("ZERRHM ",  zerrhm);
  13037.  VPUT("ZERRALRM ",zerralrm);
  13038.  
  13039.  gp->setmsg = TRUE;
  13040.  
  13041.  return;
  13042. }
  13043.  
  13044. ./ ADD NAME=GGPROC
  13045.  
  13046.  /********************************************************************/
  13047.  /*                                                                  */
  13048.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  13049.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  13050.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  13051.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  13052.  /*                                                                  */
  13053.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  13054.  /* including the implied warranties of merchantability and fitness, */
  13055.  /* are expressly denied.                                            */
  13056.  /*                                                                  */
  13057.  /* Provided this copyright notice is included, this software may    */
  13058.  /* be freely distributed and not offered for sale.                  */
  13059.  /*                                                                  */
  13060.  /* Changes or modifications may be made and used only by the maker  */
  13061.  /* of same, and not further distributed.  Such modifications should */
  13062.  /* be mailed to the author for consideration for addition to the    */
  13063.  /* software and incorporation in subsequent releases.               */
  13064.  /*                                                                  */
  13065.  /********************************************************************/
  13066.  
  13067. #pragma  csect(code,  "GG@PROC")
  13068. #pragma  csect(static,"GG$PROC")
  13069.  
  13070. #include "gg.h"
  13071.  
  13072. /*=================================================================*/
  13073.  
  13074. /****************************************************/
  13075. /* This routine "cleans" a string by removing the   */
  13076. /* leading spaces and trailing spaces and non-      */
  13077. /* graphical characters.                            */
  13078. /****************************************************/
  13079.  
  13080. static char *
  13081. trim_leading_and_trailing_space(char *string)
  13082. {
  13083.  char *str;
  13084.  
  13085.  /*  first clean up the beginning of the string... */
  13086.  
  13087.  str = skip_leading_space(string);
  13088.  
  13089.  /*    now look at the end of the string... */
  13090.  
  13091.  strip_trailing_junk_in_place(str);
  13092.  
  13093.  return str;
  13094. }
  13095.  
  13096. /*=================================================================*/
  13097.  
  13098. static void
  13099. upcase_and_append_domain_name(RECV *R,
  13100.                               char *hostname)
  13101. {
  13102.  int   hostlen;
  13103.  int   domslen;
  13104.  
  13105.  if (EQUAL(hostname,LOCAL_HOST_FROB)) return;
  13106.  
  13107.  uppercase_in_place(hostname);
  13108.  
  13109. #ifdef APPEND_DOMAIN_NAME_TO_SELF
  13110.  hostlen = strlen(hostname);
  13111.  domslen = strlen(R->mydomain);
  13112.  if (hostlen <= domslen ||
  13113.      memcmp(hostname+hostlen-domslen, R->mydomain, domslen)) {
  13114.    strncat(hostname, R->mydomain, domslen);
  13115.  }
  13116. #endif
  13117.  return;
  13118. }
  13119.  
  13120. /*=================================================================*/
  13121.  
  13122. static Bool
  13123. insure_my_name(RECV *R)
  13124. {
  13125.  
  13126.  /* Determine the local path name, if not already set. */
  13127.  
  13128.  if (!*R->myname) {
  13129.    if (gethostname(R->myname,MAXHOSTNAMELEN) < 0) {
  13130.      fprintf(stderr,"GOPHER:gethostname() failed, can't get my name\n");
  13131.      GGbarf(R,"Oops, the GOPHER server had an attack of amnesia");
  13132.      return FALSE;
  13133.    }
  13134.    upcase_and_append_domain_name(R,R->myname);
  13135.  }
  13136.  
  13137.  return TRUE;
  13138.  
  13139. }
  13140.  
  13141. /*=================================================================*/
  13142.  
  13143. static void
  13144. log_it(RRECV *R,
  13145.        char  *resource,
  13146.        Bool   rc)
  13147. {
  13148.  int          count = 0;
  13149.  char        *type;
  13150.  struct tm   *now;
  13151.  time_t       ltime;
  13152.  char         datestr [ 65];
  13153.  char         temp    [257];
  13154.  char         wtotemp [513];
  13155.  
  13156.  /* The format of a gopher log entry, as generated by the mother of
  13157.   * all gophers, is:
  13158.   *
  13159.   * Mon Oct 11 14:07:05 1993 13780 support4 : retrieved file foo/bar
  13160.   *
  13161.   */
  13162.  
  13163.  if (R->outfp) return;
  13164.  
  13165.  if (!*resource) {
  13166.    if (rc) strcpy(temp,"Root Connection");
  13167.    else    strcpy(temp,"error - Root Connection");
  13168.  }
  13169.  else {
  13170.    type = GGtype(R->pathtype);
  13171.    if (type[0] == ' ') type = "Comment";
  13172.    sprintf(temp,"%s %c%s %s",
  13173.                 rc ? "retrieved" : "error  - ",
  13174.                 tolower(type[0]), type+1, resource);
  13175.  }
  13176.  
  13177.  time(<ime);
  13178.  now = localtime(<ime);
  13179.  strftime(datestr,sizeof(datestr)-1,"%a %b %d %H:%M:%S %Y",now);
  13180.  
  13181.  sprintf(wtotemp,"%s %s %d %s : %s",
  13182.                  rc ? GOPHER_MSGID_OK : GOPHER_MSGID_ERROR,
  13183.                  datestr,
  13184.                  count,
  13185.                  /* R->hostname, suppressed for privacy reasons */
  13186.                  "{}",
  13187.                  temp);
  13188.  
  13189.  GGwto(wtotemp);
  13190.  
  13191. }
  13192.  
  13193. /*=================================================================*/
  13194.  
  13195. static Bool
  13196. authorized_file(RRECV *R)
  13197. {
  13198.  return GGacces(R,ACCESS_CHECK);  /* uses R->fileptr as argument */
  13199. }
  13200.  
  13201. /*=================================================================*/
  13202.  
  13203. /* Generic routine to begin getting data from a gopher resource. */
  13204.  
  13205. static Bool
  13206. gopher_open(RECV *R)
  13207. {
  13208.  char            *opentype;
  13209.  
  13210.  if (R->openfun) return (R->openfun)(R);
  13211.  
  13212.  if (R->binary)  opentype = "rb";
  13213.  else            opentype = "rb,type=record";
  13214.  
  13215.  if (!(R->readfile=fopen(R->buffer,opentype))) {
  13216.    perror(R->buffer);
  13217.    return FALSE;
  13218.  }
  13219.  return TRUE;
  13220.  
  13221. }
  13222.  
  13223. /*=================================================================*/
  13224.  
  13225. /* Generic routine to stop getting data from a gopher resource. */
  13226.  
  13227. static Bool
  13228. gopher_close(RECV *R)
  13229. {
  13230.  
  13231.  if (R->closefun) return (R->closefun)(R);
  13232.  
  13233.  if (!R->readfile) return FALSE;
  13234.  if (fclose(R->readfile) < 0) {
  13235.    fprintf(stderr,"GGproc: Error closing file %s\n",R->fileptr);
  13236.    return FALSE;
  13237.  }
  13238.  else return TRUE;
  13239.  
  13240. }
  13241.  
  13242. /*=================================================================*/
  13243.  
  13244. /* Generic routine to get text data from a gopher resource. */
  13245.  
  13246. static Bool
  13247. gopher_read(RECV *R)
  13248. {
  13249.  char            *cp;
  13250.  
  13251.  if (R->readfun) return (R->readfun)(R);
  13252.  
  13253.  memset(R->buffer,0,RBUFSIZE);
  13254.  
  13255.  if (R->binary) {
  13256.    R->bytes_read = fread(R->buffer,sizeof(char),RBUFSIZE,R->readfile);
  13257.  }
  13258.  else {
  13259.    (void)fread(R->buffer,RBUFSIZE,1,R->readfile);
  13260.  }
  13261.  if (ferror(R->readfile)) {
  13262.    fprintf(stderr,"GGproc: gopher_read: Error reading file\n");
  13263.    R->readstatus = STATUS_ERROR;
  13264.    return FALSE;
  13265.  }
  13266.  else if (feof(R->readfile)) {
  13267.    R->readstatus = STATUS_EOF;
  13268.    return FALSE;
  13269.  }
  13270.  if (!R->binary) {
  13271.    if ((cp=strchr(R->buffer,'\n'))) *cp = '\0';
  13272.    strip_trailing_in_place(R->buffer);
  13273.  }
  13274.  R->readstatus = STATUS_OK;
  13275.  return TRUE;
  13276.  
  13277. }
  13278.  
  13279. /*=================================================================*/
  13280.  
  13281. /*******************************************************************/
  13282. /*            This routine figures out what type of parm line      */
  13283. /*            the current line is.  We'll return the token         */
  13284. /*            type to the caller.                                  */
  13285. /*                                                                 */
  13286. /*            INPUT:   buffer  pointer to first line of file       */
  13287. /*                       (Note: string must be null terminated!    */
  13288. /*            OUTPUT:   Type of token.  (See in include file...)   */
  13289. /*******************************************************************/
  13290.  
  13291. static int
  13292. menukeywd(char  *buffer,
  13293.           char  *token,
  13294.           char  *operand)
  13295. {
  13296.  char           *cp;
  13297.  char           *tokval;
  13298.  char           *oprval;
  13299.  char           *tokptr;
  13300.  char            tokstr[256];
  13301.  
  13302.  strcpy(token,"");
  13303.  strcpy(operand,"");
  13304.  switch (buffer[0]) {
  13305.    case TOKCOMMENT1:
  13306.    case TOKCOMMENT2:
  13307.    case TOKCOMMENT3: return COMMENTTOK;
  13308.  }
  13309.  strcpy(tokstr,buffer);
  13310.  cp = strchr(tokstr,'=');
  13311.  if (cp) {
  13312.    *cp = '\0';
  13313.    strcpy(operand,cp+1);
  13314.  }
  13315.  tokptr = skip_leading_space(tokstr);
  13316.  uppercase_in_place(tokptr);
  13317.  strcpy(token,tokptr);
  13318.  
  13319.  /*********/
  13320.  /*  now look at the tokens to see if we have a weener... */
  13321.  /*********/
  13322.  
  13323.  if(EQUAL(tokptr,TOKTYPE)) return(TYPETOK);
  13324.  if(EQUAL(tokptr,TOKNAME)) return(NAMETOK);
  13325.  if(EQUAL(tokptr,TOKPATH)) return(PATHTOK);
  13326.  if(EQUAL(tokptr,TOKHOST)) return(HOSTTOK);
  13327.  if(EQUAL(tokptr,TOKPORT)) return(PORTTOK);
  13328.  if(EQUAL(tokptr,TOKEND))  return(ENDTOK);
  13329.  
  13330.  /* for back compatibility with the old MVS GOPHER server */
  13331.  
  13332.  if(EQUAL(tokptr,TOKDISPLAY)) return(DISPLAYTOK);
  13333.  if(EQUAL(tokptr,TOKSELECT))  return(SELECTTOK);
  13334.  if(EQUAL(tokptr,TOKSELECT))  return(SELECTTOK);
  13335.  
  13336.  return(NULLTOK);
  13337.  
  13338. }
  13339.  
  13340. /*=================================================================*/
  13341.  
  13342. /*******************************************************************/
  13343. /*   This routine sends a file to the calling client.              */
  13344. /*   It assumes the file is a text formatted file.                 */
  13345. /*   INPUT:   buffer    pointer to the already read line...        */
  13346. /*            readfile  file we're going to read from..            */
  13347. /*            maxlen    size of the buffer.                        */
  13348. /*            sockfd    socket descriptor for client.              */
  13349. /*                                                                 */
  13350. /*   OUTPUT:   send the file to the client                         */
  13351. /*******************************************************************/
  13352. static void
  13353. sendafile(RECV *R)
  13354. {
  13355.  
  13356.  /*******/
  13357.  /*   send the first line (cause we already read it) */
  13358.  /*******/
  13359.  
  13360.  if (!GGouts(R,R->buffer,NO_VALUE)) return;
  13361.  
  13362.  /*******/
  13363.  /*   get the rest of the lines of the file and send them... */
  13364.  /*******/
  13365.  
  13366.  for (;;) {
  13367.    gopher_read(R);
  13368.    switch (R->readstatus) {
  13369.      case STATUS_ERROR:
  13370.       (void)GGouts(R,"<<<*** I/O ERROR ON MVS FILE ***>>>",NO_VALUE);
  13371.       return;
  13372.      case STATUS_EOF:
  13373.       break;
  13374.      default:
  13375.       if (!GGouts(R,R->buffer,NO_VALUE)) return;
  13376.       continue;
  13377.    }
  13378.    break;
  13379.  }
  13380. }
  13381.  
  13382. /*=================================================================*/
  13383.  
  13384. static void
  13385. senderrors(RECV *R)
  13386. {
  13387.  
  13388.  for (;;) {
  13389.    gopher_read(R);
  13390.    switch (R->readstatus) {
  13391.      case STATUS_ERROR:
  13392.       (void)GGouts(R,"<<<*** I/O ERROR ON MVS FILE ***>>>",NO_VALUE);
  13393.       return;
  13394.      case STATUS_EOF:
  13395.       break;
  13396.      default:
  13397.       if (R->pathtype == GOPHER_MENU) GGbarf(R,R->buffer);
  13398.       else (void)GGouts(R,R->buffer,NO_VALUE);
  13399.       continue;
  13400.    }
  13401.    break;
  13402.  }
  13403. }
  13404.  
  13405. /*=================================================================*/
  13406.  
  13407. /*******************************************************************/
  13408. /*   This routine formats a menu file into gopher data & sends it  */
  13409. /*   to the client.                                                */
  13410. /*   INPUT:   buffer    pointer to the already read line...        */
  13411. /*            readfile  file we're going to read from..            */
  13412. /*            maxlen    size of the buffer.                        */
  13413. /*            sockfd    socket descriptor for client               */
  13414. /*                                                                 */
  13415. /*   OUTPUT:   send the menu to the client                         */
  13416. /*******************************************************************/
  13417.  
  13418. #define MENU_STUFF_SIZE GOPHER_DESC_LENGTH + \
  13419.                         GOPHER_PATH_LENGTH + \
  13420.                         GOPHER_HOST_LENGTH + 20
  13421.  
  13422. static void
  13423. sendamenu(RECV *R)
  13424. {
  13425.  char           *operptr;
  13426.  char           *tot;                    /*pointer for strtok   */
  13427.  char           *cp;
  13428.  int             kindotoken;
  13429.  int             i;
  13430.  char            token   [133];
  13431.  char            operand [133];
  13432.  char            outbuf  [MENU_STUFF_SIZE];
  13433.  char            uphost  [GOPHER_HOST_LENGTH+1];
  13434.  MENUITEM        menu;
  13435.  
  13436.  CLEAR(&menu);
  13437.  for (;;) {
  13438.    gopher_read(R);
  13439.    if (R->readstatus != STATUS_OK) break;  /* error or end of file */
  13440.    if (!*R->buffer) continue;
  13441.    kindotoken = menukeywd(R->buffer,token,operand);
  13442.    switch(kindotoken) {
  13443.      case TYPETOK:
  13444.           operptr = skip_whitespace(operand);
  13445.           tot = strtok(operptr," ");
  13446.           i = strlen(tot);
  13447.           menu.gopherplus = '\0';
  13448.           if (i > 1) {
  13449.             cp = &tot[i-1];
  13450.             switch (*cp) {
  13451.               case '+': /* regular gopher+ item */
  13452.               case '?': /* ASK block item */
  13453.                         menu.gopherplus = *cp;
  13454.                         *cp = '\0';
  13455.                         i--;
  13456.                         break;
  13457.               default:  break;
  13458.             }
  13459.           }
  13460.           if (i == 1) menu.type = *tot;
  13461.           else {
  13462.             uppercase_in_place(tot);
  13463.             if      (EQUAL(tot,TYPEFILE))   menu.type = GOPHER_FILE;
  13464.             else if (EQUAL(tot,TYPEMENU))   menu.type = GOPHER_MENU;
  13465.             else if (EQUAL(tot,TYPECSO))    menu.type = GOPHER_CSO;
  13466.             else if (EQUAL(tot,TYPEINDEX))  menu.type = GOPHER_INDEX;
  13467.             else if (EQUAL(tot,TYPETELNET)) menu.type = GOPHER_TELNET;
  13468.             else if (EQUAL(tot,TYPETN3270)) menu.type = GOPHER_TN3270;
  13469.             else if (EQUAL(tot,TYPEBINARY)) menu.type = GOPHER_BINARY;
  13470.             else if (EQUAL(tot,TYPEWHOIS))  menu.type = GOPHER_WHOIS;
  13471.             else if (EQUAL(tot,TYPEBOOKMANAGER))
  13472.                                         menu.type = GOPHER_BOOKMANAGER;
  13473.             else                        menu.type = GOPHER_ERROR;
  13474.           }
  13475.           break;
  13476.      case NAMETOK:
  13477.      case DISPLAYTOK:
  13478.           strncpy(menu.desc, operand, sizeof(menu.desc));
  13479.           break;
  13480.      case PATHTOK:
  13481.      case SELECTTOK:
  13482.           operptr = skip_whitespace(operand);
  13483.           strncpy(menu.select, operptr, sizeof(menu.select));
  13484.           break;
  13485.      case HOSTTOK:
  13486.           *menu.hostname = '\0';
  13487.           if (EQUAL(operptr,IDENT_HOST_FROB)) {  /* HOST=+  */
  13488.             strncpy(menu.hostname, R->myname, sizeof(menu.hostname));
  13489.           }
  13490.           else {
  13491.             operptr = skip_whitespace(operand);
  13492.             strncpy(menu.hostname, operptr, sizeof(menu.hostname));
  13493.           }
  13494.           strcpy(uphost, menu.hostname);
  13495.           upcase_and_append_domain_name(R,uphost);
  13496.  
  13497.           break;
  13498.      case PORTTOK:
  13499.           operptr = skip_whitespace(operand);
  13500.           if (EQUAL(operptr,IDENT_HOST_FROB))    /* PORT=+  */
  13501.                menu.port = R->myport;
  13502.           else menu.port = atoi(operptr);
  13503.           break;
  13504.      case ENDTOK:
  13505.      case COMMENTTOK:
  13506.           if (menu.port == 0) {
  13507.             switch (menu.type) {
  13508.               case GOPHER_TELNET: break;
  13509.               case GOPHER_TN3270: break;
  13510.               default: menu.port = GOPHER_PORT_NUMBER; break;
  13511.             }
  13512.           }
  13513.           /* If host is local and path is in the form "(member)",
  13514.            * and current dsname is a PDS, then use same PDS:
  13515.            * i.e. turn PATH=(FOOBAR) into PATH=AA.BB.CC(FOOBAR)
  13516.            */
  13517.           if (*R->myname
  13518.            && EQUAL(uphost, R->myname)
  13519.            && *menu.select == '('        /* ) */
  13520.            && (cp = strchr(R->dsname,'(' /* ) */ ))) {
  13521.             memcpy(outbuf, R->dsname, (cp-R->dsname));
  13522.             strcpy(outbuf+(cp-R->dsname), menu.select);
  13523.             strncpy(menu.select, outbuf, sizeof(menu.select));
  13524.           }
  13525.           if (menu.type && *menu.desc && *menu.hostname) {
  13526.             sprintf(outbuf,"%c%s\t%s\t%s\t%d%c%c",
  13527.                            menu.type,menu.desc,
  13528.                            menu.select,menu.hostname,menu.port,
  13529.                            menu.gopherplus ? '\t' : '\0',
  13530.                            menu.gopherplus);
  13531.             if (!GGouts(R,outbuf,NO_VALUE)) return;
  13532.           }
  13533.           fflush(stdout);
  13534.           CLEAR(&menu);
  13535.           break;
  13536.      default:
  13537.           break;
  13538.        }
  13539.    }
  13540. }
  13541.  
  13542. /*=================================================================*/
  13543.  
  13544. /*******************************************************************/
  13545. /*            This routine determines what type of gopher file     */
  13546. /*            we've opened.  We'll return the file type to the     */
  13547. /*            caller.                                              */
  13548. /*                                                                 */
  13549. /*            INPUT:   ident   pointer to first line of file       */
  13550. /*                                                                 */
  13551. /*            OUTPUT:   MENU   file type is a menu                 */
  13552. /*                      FILE   file type is a file                 */
  13553. /*                      BINARY file type is binary                 */
  13554. /*                      INDEX  file type is an INDEX (not done)    */
  13555. /*******************************************************************/
  13556.  
  13557. static char
  13558. getftype(RECV *R)
  13559. {
  13560.  char *bufptr;
  13561.  char  buffer[RBUFSIZE];
  13562.  
  13563.  /* If a type was found in the path, use that type. */
  13564.  
  13565.  if (R->pathtype) return R->pathtype;
  13566.  
  13567.  /**********/
  13568.  /*    else, convert the string to upper case...   */
  13569.  /*********/
  13570.  copy_uppercase(buffer,R->buffer);
  13571.  bufptr = skip_leading_space(buffer);
  13572.  
  13573.  /**********/
  13574.  /*   return the type of file.                     */
  13575.  /*********/
  13576.  
  13577.  if      (EQUAL(bufptr,MENUIDENT))  R->pathtype = GOPHER_MENU;
  13578.  else if (EQUAL(bufptr,INDEXIDENT)) R->pathtype = GOPHER_INDEX;
  13579.  else /* dunno, assume it's file */ R->pathtype = GOPHER_FILE;
  13580.  
  13581.  return(R->pathtype);
  13582.  
  13583. }
  13584.  
  13585. /*=================================================================*/
  13586.  
  13587. static Bool
  13588. get_directory(RECV *R)
  13589. {
  13590.  FILE              *dirfile;
  13591.  char              *cp;
  13592.  char              *mp;
  13593.  int                i;
  13594.  short              block_count;
  13595.  short              bump_amount;
  13596.  Bool               reject;
  13597.  Bool               no_more;
  13598.  char               dirblk  [256];
  13599.  char               pdsspec [256];
  13600.  char               entry   [256];
  13601.  
  13602.  /* The local path name is required for this function. */
  13603.  
  13604.  if (!(dirfile=fopen(R->buffer,"rb,recfm=u,lrecl=256"))) {
  13605.    perror(R->buffer);
  13606.    printf("Can't open PDS directory:%s\n",R->dsname);
  13607.    GGbarf(R,"Sorry, the GOPHER server can't open the directory");
  13608.    return(FALSE);
  13609.  }
  13610.  
  13611.  while (!feof(dirfile)) {
  13612.  
  13613.    no_more = FALSE;
  13614.  
  13615.    do {
  13616.      memset(dirblk,0x00,256);
  13617.      fread(dirblk,256,1,dirfile);
  13618.      if (feof(dirfile)) break;
  13619.      if (ferror(dirfile)) {
  13620.        printf("Can't read PDS directory:%s\n", R->fileptr);
  13621.        GGbarf(R,"Sorry, the GOPHER server can't read the directory");
  13622.        fclose(dirfile);
  13623.        return FALSE;
  13624.      }
  13625.      mp = dirblk;
  13626.      block_count = *(short *)mp - 2;   /* # bytes in dir block */
  13627.      mp += 2;                        /* addr of dir block data */
  13628.      while (block_count > 0) {
  13629.        if (!memcmp(mp,"\xff\xff\xff\xff\xff\xff\xff\xff",8)) break;
  13630.        reject = FALSE;
  13631.        /*
  13632.         * Uncomment this if you want to skip aliases.
  13633.         * It is recommended that you let aliases through, since
  13634.         * they often have better names (e.g. TSO HELP files)
  13635.         *
  13636.         * if ((mp[11] & 0x80) != 0) {
  13637.         *   fprintf(stderr,"Skipping alias:  %-8.8s\n",mp);
  13638.         *   reject = TRUE;
  13639.         * }
  13640.         */
  13641.        if (!reject) {
  13642.          strcpy(pdsspec, R->dsname);
  13643.          cp = strchr(pdsspec, '\0');
  13644.          *(cp++) = '(';
  13645.          for (i = 0; i < 8 && mp[i] != ' '; cp++, i++) *cp = mp[i];
  13646.          *(cp++) = ')';
  13647.          *cp = '\0';
  13648.          sprintf(entry,"0%8.8s\t%s\t%s\t%d",
  13649.                        mp, pdsspec, R->myname, SERV_TCP_PORT);
  13650.          (void)GGouts(R,entry,NO_VALUE);
  13651.        }
  13652.        bump_amount = 12 + ((mp[11] & 0x1f) * 2);
  13653.        mp += bump_amount;
  13654.        block_count -= bump_amount;
  13655.      }
  13656.    } while(!no_more);
  13657.  }
  13658.  
  13659.  fclose(dirfile);
  13660.  return TRUE;
  13661. }
  13662.  
  13663. /*=================================================================*/
  13664.  
  13665. static Bool
  13666. get_flat_file(RECV *R)
  13667. {
  13668.  
  13669.  if (!gopher_open(R)) {
  13670.    printf("INVALID! requested:%s\n",R->fileptr);
  13671.    GGbarf(R,"Sorry, the GOPHER server couldn't open the file");
  13672.    return(FALSE);
  13673.  }
  13674.  
  13675.  /* A gopher+ client wants a success indication plus "-1", which
  13676.     means the following data is delivered in dot-stuffing mode. */
  13677.  
  13678.  if (R->gopherplus) {
  13679.    if (!GGouts(R,"+-1",OUT_PLUS)) return FALSE;
  13680.  }
  13681.  
  13682.  /************/
  13683.  /*  get the first line and see what type of file we've got.      */
  13684.  /************/
  13685.  
  13686.  gopher_read(R);
  13687.  if (R->readstatus == STATUS_OK) {
  13688.  
  13689.   /************/
  13690.   /*  Now let's go do whatever we need to for this file type.    */
  13691.   /************/
  13692.  
  13693.    switch (getftype(R)) {
  13694.  
  13695.      case GOPHER_MENU:
  13696.                  sendamenu(R);
  13697.                  break;
  13698.      case GOPHER_FILE:
  13699.      default:
  13700.                  sendafile(R);
  13701.                  break;
  13702.    }
  13703.  
  13704.  }
  13705.  
  13706.  if (!gopher_close(R)) {
  13707.    GGbarf(R,"Sorry, the GOPHER server couldn't close the file");
  13708.    return FALSE;
  13709.  }
  13710.  
  13711.  return TRUE;
  13712.  
  13713. }
  13714.  
  13715. /*=================================================================*/
  13716.  
  13717. static Bool
  13718. get_error_file(RECV *R)
  13719. {
  13720.  
  13721.  if (!gopher_open(R)) {
  13722.    printf("INVALID! requested:%s\n",R->fileptr);
  13723.    GGbarf(R,"Sorry, the GOPHER server couldn't open the file");
  13724.    return(FALSE);
  13725.  }
  13726.  
  13727.  senderrors(R);
  13728.  
  13729.  if (!gopher_close(R)) {
  13730.    GGbarf(R,"Sorry, the GOPHER server couldn't close the file");
  13731.    return FALSE;
  13732.  }
  13733.  
  13734.  return TRUE;
  13735.  
  13736. }
  13737.  
  13738. /*=================================================================*/
  13739.  
  13740. static Bool
  13741. get_binary_file(RECV *R)
  13742. {
  13743.  
  13744.  if (!gopher_open(R)) {
  13745.    printf("INVALID! requested:%s\n",R->fileptr);
  13746.    GGbarf(R,"Sorry, the GOPHER server couldn't open the binary file");
  13747.    return(FALSE);
  13748.  }
  13749.  
  13750.  /* A gopher+ client wants a success indication plus "-2", which
  13751.     means the following data is delivered in dump-till-close mode. */
  13752.  
  13753.  if (R->gopherplus) {
  13754.    if (!GGouts(R,"+-2",OUT_PLUS)) return FALSE;
  13755.  }
  13756.  
  13757.  for (;;) {
  13758.    gopher_read(R);
  13759.    if (R->bytes_read > 0) {
  13760.      if (!GGouts(R,R->buffer,R->bytes_read)) return FALSE;
  13761.    }
  13762.    switch (R->readstatus) {
  13763.      case STATUS_ERROR:
  13764.       (void)GGouts(R,"<<<*** I/O ERROR ON MVS FILE ***>>>",NO_VALUE);
  13765.       return FALSE;
  13766.      case STATUS_EOF:
  13767.       break;
  13768.      default:
  13769.       continue;
  13770.    }
  13771.    break;
  13772.  }
  13773.  
  13774.  if (!gopher_close(R)) {
  13775.    GGbarf(R,"Sorry, the GOPHER server couldn't close the file");
  13776.    return FALSE;
  13777.  }
  13778.  
  13779.  return TRUE;
  13780.  
  13781. }
  13782.  
  13783. /*=================================================================*/
  13784.  
  13785. static Bool
  13786. get_as_file(RECV *R)
  13787. {
  13788.  
  13789.  switch (R->pathtype) {
  13790.    case GOPHER_MAC_BINHEX:
  13791.    case GOPHER_DOS_BINARCH:
  13792.    case GOPHER_IMAGE:
  13793.    case GOPHER_BINARY:
  13794.    case GOPHER_BOOKMANAGER:
  13795.              R->binary = TRUE;
  13796.              return get_binary_file(R);
  13797.    default:
  13798.              R->binary = FALSE;
  13799.              return get_flat_file(R);
  13800.  }
  13801.  
  13802. }
  13803.  
  13804. /*=================================================================*/
  13805.  
  13806. static Bool
  13807. get_exec_data(RECV *R)
  13808. {
  13809.  
  13810.  GGCB              *gp = NULL;     /* for GETMAIN and FREEMAIN */
  13811.  char              *command;
  13812.  char              *commandargs;
  13813.  int                rexxrc;
  13814.  int                cmdlen;
  13815.  int                scan_count;
  13816.  int                i;
  13817.  Bool               rc;
  13818.  char               exectest[RBUFSIZE];
  13819.  
  13820.   /*
  13821.    * Menu item should look like this:
  13822.    *
  13823.    * exec:rexxname any args
  13824.    *
  13825.    * The exec should write output to SYSTSPRT.  Normal TSO command
  13826.    * output will be captured by the SYSTSPRT allocation only if
  13827.    * the Gopher server is run as a batch job.
  13828.    *
  13829.    * If this was sent by the client with a type 7 or type w, then
  13830.    * additional args will appear at the end delimited by a space.
  13831.    */
  13832.  
  13833.  rc = TRUE;
  13834.  scan_count = 0;
  13835.  
  13836.  if (R->wargptr) {
  13837.    cmdlen = strlen(R->fileptr) + strlen(R->wargptr) + 4;
  13838.    GETMAIN(command, char, cmdlen, "REXX command buffer");
  13839.    if (!command) {
  13840.      printf("Cannot allocate %d bytes of memory for exec\n", cmdlen);
  13841.      GGbarf(R,"Oops, the GOPHER server ran out of memory");
  13842.      return FALSE;
  13843.    }
  13844.    else sprintf(command,"%s %s",R->fileptr,R->wargptr);
  13845.  }
  13846.  else {
  13847.    cmdlen = 0;
  13848.    command = R->fileptr;
  13849.  }
  13850.  
  13851.  *exectest = '\0';
  13852.  sscanf(command, "%s %n", exectest, &scan_count);
  13853.  if (strlen(exectest) > 8) {
  13854.    GGbarf(R,"Sorry, name of exec is too long");
  13855.    return FALSE;
  13856.  }
  13857.  commandargs = command + scan_count;
  13858.  
  13859.  if (rc) {
  13860.  
  13861.    rexxrc = GGrexx(R,exectest,commandargs);
  13862.  
  13863.    if (!R->outfp) printf("Return code from %s exec is %d\n",
  13864.                          exectest, rexxrc);
  13865.  
  13866.    if (rexxrc != 0) {
  13867.      GGbarf(R,"Sorry, the Gopher server was unable to run the exec");
  13868.      rc = FALSE;
  13869.    }
  13870.    else {
  13871.      rc = get_as_file(R);         /* Display what the exec wrote */
  13872.    }
  13873.  
  13874.  }
  13875.  
  13876.  if (cmdlen > 0) FREEMAIN(command, "REXX command buffer");
  13877.  return rc;
  13878.  
  13879. }
  13880.  
  13881. /*=================================================================*/
  13882.  
  13883. static Bool
  13884. get_ftp_data(RECV        *R,
  13885.              GOPHERTYPE   ftptype,
  13886.              char        *resource,
  13887.              OSTYPE       ftpos,
  13888.              char        *ftpprefix
  13889.             )
  13890. {
  13891.   /*
  13892.    * FTP hack.  The syntax is:
  13893.    * ftp0:host:path
  13894.    * ftp0:host:user:path
  13895.    * ftp0:host:user:pass:path
  13896.    * ftp1:host
  13897.    * ftp1:host:path
  13898.    * ftp1:host:user:path
  13899.    * ftp1:host:user:pass:path
  13900.    *
  13901.    * ftpvm0:vmhost:disk/path
  13902.    * ftpvm1:vmhost:disk
  13903.    *
  13904.    * ftp0 means ftp a file.
  13905.    * ftp1 means ftp a directory.
  13906.    * Obviously, ftp0:host cannot exist, because that will always
  13907.    *            look for a remote FTP directory.
  13908.    *
  13909.    * If path is omitted, then path is remote ftp current directory
  13910.    * If user is omitted, defaults to "anonymous".
  13911.    * If pass is omitted, defaults to "client@localhost.domain.qual"
  13912.    *
  13913.    * The syntax is defined to let path always be the last item
  13914.    * just in case the path name contains a colon.
  13915.    *
  13916.    * For backward compatibility for a very short time, the form
  13917.    * ftp:host(other stuff) will be permitted.  When this is used,
  13918.    * due to the limitations of the Gopher protocol, the only way to
  13919.    * let the server know that a directory instead of a file is wanted
  13920.    * is to append "/" to the end of the path.
  13921.    *
  13922.    * And, of course, if the path is omitted then that's got to be a
  13923.    * directory request as well.
  13924.    *
  13925.    * Note for the FTP options
  13926.    *       No authorized-file check is done, because we assume that
  13927.    *       any file available via anonymous ftp is wide open to the
  13928.    *       world to begin with.  Besides, we can't possibly specify
  13929.    *       every remote file in the entire universe, now, can we?
  13930.    */
  13931.  
  13932.  char              *ftpword1;
  13933.  char              *ftpword2;
  13934.  char              *ftpword3;
  13935.  char              *ftpword4;
  13936.  char              *cp;
  13937.  GOPHERTYPE         savetype;
  13938.  struct Ftp        *F;
  13939.  Bool               ftpok;
  13940.  IOMODE             crmode;
  13941.  struct Ftp         ftp;
  13942.  TEMPFILE           outtemp;
  13943.  TEMPFILE           errtemp;
  13944.  
  13945.  ftpok    = FALSE;
  13946.  ftpword1 = R->fileptr;
  13947.  ftpword2 = "";
  13948.  ftpword3 = "";
  13949.  ftpword4 = "";
  13950.  
  13951.  F = &ftp;
  13952.  CLEAR(F);
  13953.  
  13954.  cp = strchr(ftpword1,':');
  13955.  if (cp) {
  13956.    *cp = '\0';
  13957.    ftpword2 = cp + 1;
  13958.    cp = strchr(ftpword2,':');
  13959.    if (cp) {
  13960.      *cp = '\0';
  13961.      ftpword3 = cp + 1;
  13962.      cp = strchr(ftpword3,':');
  13963.      if (cp) {
  13964.        *cp = '\0';
  13965.        ftpword4 = cp + 1;
  13966.      }
  13967.    }
  13968.  }
  13969.  strncpy(F->host, ftpword1, sizeof(F->host));
  13970.  if (*ftpword2) {
  13971.    if (*ftpword3) {
  13972.      if (*ftpword4) {
  13973.        strncpy(F->user, ftpword2, sizeof(F->user));
  13974.        strncpy(F->pass, ftpword3, sizeof(F->pass));
  13975.        strncpy(F->path, ftpword4, sizeof(F->path));
  13976.      }
  13977.      else {
  13978.        strncpy(F->user, ftpword2, sizeof(F->user));
  13979.        strncpy(F->path, ftpword3, sizeof(F->path));
  13980.      }
  13981.    }
  13982.    else {
  13983.      strncpy(F->path, ftpword2, sizeof(F->path));
  13984.    }
  13985.  }
  13986.  
  13987.  /* Set defaults for path, user and pass if omitted.
  13988.   * Note that the password is set to client@site.  If the site is
  13989.   * the "local" frob, then set it to the domain name, minus the
  13990.   * initial dot that should be there if you configured your MVS
  13991.   * gopher properly.
  13992.   */
  13993.  
  13994.  if (!*F->path) strcpy(F->path,"/");
  13995.  if (!*F->user) strcpy(F->user,"anonymous");
  13996.  if (!*F->pass) {
  13997.  
  13998.    /* should this be foo.draper.com@mvs.draper.com
  13999.     * or gopher@foo.draper.com?
  14000.     *
  14001.     * sprintf(F->pass,"%s@%s",R->hostname,
  14002.     *   EQUAL(R->myname,LOCAL_HOST_FROB) ? R->mydomain+1 : R->myname);
  14003.     * or
  14004.     * sprintf(F->pass,"gopher@%s",R->hostname);
  14005.     *
  14006.     */
  14007.  
  14008.    strcpy(F->pass,"gopher@");
  14009.  
  14010. #ifdef BLAB_MACHINE_NAME_TO_THE_WORLD
  14011.  
  14012.    if (*R->hostname)  strcat(F->pass,R->hostname);
  14013.    else if (EQUAL(R->myname,LOCAL_HOST_FROB))
  14014.                       strcat(F->pass,R->mydomain+1);
  14015.    else               strcat(F->pass,R->myname);
  14016.  
  14017. #else
  14018.  
  14019.    strcat(F->pass,R->mydomain+1);
  14020.  
  14021. #endif
  14022.  
  14023.  }
  14024.  
  14025.  F->os = ftpos;
  14026.  strcpy(F->ftphack, ftpprefix);
  14027.  
  14028.  switch (ftptype) {
  14029.    case GOPHER_UNKNOWN: /* compatibility mode */
  14030.             cp = F->path + strlen(F->path) - 1;
  14031.             if (*cp == '/') {
  14032.               *cp = '\0';
  14033.               F->type = GOPHER_DIRECTORY;
  14034.             }
  14035.             else F->type = GOPHER_FILE;
  14036.             crmode = CRLF;
  14037.             break;
  14038.    case GOPHER_MAC_BINHEX:
  14039.    case GOPHER_DOS_BINARCH:
  14040.    case GOPHER_IMAGE:
  14041.    case GOPHER_BINARY:
  14042.    case GOPHER_BOOKMANAGER:
  14043.             F->type = ftptype;
  14044.             crmode = RBIN;
  14045.             break;
  14046.    default:
  14047.             F->type = ftptype;
  14048.             crmode = CRLF;
  14049.             break;
  14050.  }
  14051.  
  14052.  R->pathtype = F->type;
  14053.  
  14054.  /* Set resource name for logging.  This is to conform with the
  14055.   * UMn Gopher syntax and also to suppress usernames and passwords.
  14056.   */
  14057.  
  14058.  sprintf(resource,"ftp:%s@%s",F->host,F->path);
  14059.  
  14060.  /* Create temporary files for FTP output. */
  14061.  
  14062.  CLEAR(&outtemp);
  14063.  CLEAR(&errtemp);
  14064.  outtemp.crmode = crmode;
  14065.  errtemp.crmode = CRLF;
  14066.  
  14067.  F->outfp = GGtemp(R,&outtemp,TEMP_CREATE);
  14068.  F->errfp = GGtemp(R,&errtemp,TEMP_CREATE);
  14069.  
  14070.  if (!F->outfp || !F->errfp) {
  14071.    GGbarf(R,
  14072.    "Sorry, the GOPHER server couldn't service the remote FTP request");
  14073.    return FALSE;
  14074.  }
  14075.  
  14076.  if (!memcmp(ftpprefix,"FTPDEBUG",8)) F->verboseflag = TRUE;
  14077.  
  14078.  ftpok = GGftp(R,F);
  14079.  
  14080.  fflush(F->outfp);
  14081.  fflush(F->errfp);
  14082.  
  14083.  /* Close temporary files. */
  14084.  
  14085.  F->outfp = GGtemp(R,&outtemp,TEMP_CLOSE);
  14086.  F->errfp = GGtemp(R,&errtemp,TEMP_CLOSE);
  14087.  
  14088.  if (!F->outfp || !F->errfp) {
  14089.    GGbarf(R,
  14090.    "Sorry, the GOPHER server couldn't service the remote FTP request");
  14091.    return FALSE;
  14092.  }
  14093.  
  14094.  
  14095.  if (ftpok) {
  14096.    savetype = R->pathtype;
  14097.    if (R->pathtype == GOPHER_MENU) R->pathtype = GOPHER_UNKNOWN;
  14098.    strcpy(R->buffer, outtemp.dsname);
  14099.    ftpok = get_as_file(R);
  14100.    if (savetype != GOPHER_UNKNOWN) R->pathtype = savetype;
  14101.  }
  14102.  else {
  14103.    strcpy(R->buffer, errtemp.dsname);
  14104.    R->binary = FALSE;
  14105.    ftpok = get_error_file(R);
  14106.  }
  14107.  
  14108.  /* Remove temporary files. */
  14109.  
  14110.  F->outfp = GGtemp(R,&outtemp,TEMP_REMOVE);
  14111.  F->errfp = GGtemp(R,&errtemp,TEMP_REMOVE);
  14112.  
  14113.  if (!F->outfp || !F->errfp) {
  14114.    GGbarf(R,
  14115.    "Sorry, the GOPHER server couldn't service the remote FTP request");
  14116.    return FALSE;
  14117.  }
  14118.  
  14119.  return ftpok;
  14120.  
  14121. }
  14122.  
  14123. /*=================================================================*/
  14124.  
  14125. static Bool
  14126. get_info(RRECV *R,
  14127.          char  *resource)
  14128. {
  14129.  int               hacksize;      /* length of hack prefix before : */
  14130.  Bool              rc;            /* return value */
  14131.  DSTYPE            dsntype;       /* SEQ, PDS or UNK */
  14132.  char             *p;
  14133.  char             *q;
  14134.  char             *colonptr;
  14135.  char              ddname    [  9];
  14136.  char              hackprefix[ 17];
  14137.  
  14138.  *ddname     = '\0';
  14139.  *hackprefix = '\0';
  14140.  
  14141.  /*
  14142.   * Process special hacks here.
  14143.   *
  14144.   * For example, if the file name begins with "exec:", then
  14145.   * execute the specified REXX exec.
  14146.   *
  14147.   * Hackless names are processed as files.  "dd:" is not a
  14148.   * special hack but the normal C/370 DDname reference.
  14149.   *
  14150.   */
  14151.  
  14152.  colonptr = strchr(R->fileptr,':');
  14153.  if (colonptr) {
  14154.    hacksize = colonptr - R->fileptr;
  14155.    if (hacksize > 0 && hacksize < sizeof(hackprefix)) {
  14156.      for (p = hackprefix, q = R->fileptr;
  14157.           hacksize > 0;
  14158.           p++, q++, hacksize--) *p = toupper(*q);
  14159.      *p = '\0';
  14160.    }
  14161.  }
  14162.  
  14163.  if (EQUAL(hackprefix,"EXEC")) {
  14164.   /*
  14165.    * REXX exec, which must reside in GGEXEC DD.
  14166.    */
  14167.    if (!authorized_file(R)) {
  14168.      GGbarf(R,"Sorry, the GOPHER server won't run the exec for you");
  14169.      rc = FALSE;
  14170.    }
  14171.    else {
  14172.      R->fileptr = colonptr + 1;  /* point to exec itself */
  14173.      rc = get_exec_data(R);
  14174.    }
  14175.  }
  14176.  else
  14177.  if (EQUAL(hackprefix,"DD")) {
  14178.   /*
  14179.    * C/370 style ddname.  Assume sequential file - cannot be a PDS
  14180.    * because I don't feel like trying to determine that right now.
  14181.    */
  14182.    if (!authorized_file(R)) {
  14183.      GGbarf(R,"Sorry, the GOPHER server won't read the DD for you");
  14184.      rc = FALSE;
  14185.    }
  14186.    else {
  14187.      strcpy(R->buffer,R->fileptr); /* still points to "DD:xxxxxxxx" */
  14188.      strcpy(R->dsname,R->buffer);  /* needed for PATH=(member) check */
  14189.      dsntype = SEQ;
  14190.      rc = get_as_file(R);
  14191.    }
  14192.  }
  14193.  else
  14194.  if (strlen(hackprefix) == 4 && !memcmp(hackprefix,"FTP",3)) {
  14195.    R->fileptr = colonptr + 1;  /* point to ftp locator */
  14196.    rc = get_ftp_data(R,hackprefix[3],resource,DEFAULT_OS,"FTP");
  14197.  }
  14198.  else
  14199.  if (strlen(hackprefix) == 9 && !memcmp(hackprefix,"FTPDEBUG",8)) {
  14200.    R->fileptr = colonptr + 1;  /* point to ftp locator */
  14201.    rc = get_ftp_data(R,hackprefix[8],resource,DEFAULT_OS,"FTPDEBUG");
  14202.  }
  14203.  else
  14204.  if (strlen(hackprefix) == 6 && !memcmp(hackprefix,"FTPVM",5)) {
  14205.    R->fileptr = colonptr + 1;  /* point to ftp locator */
  14206.    rc = get_ftp_data(R,hackprefix[5],resource,VM_OS,"FTPVM");
  14207.  }
  14208.  else {
  14209.    /* Regular file name without ":" hack, or with invalid ":" hack.
  14210.     * Check to see that the file name is on our "official" list.
  14211.     */
  14212.    if (!authorized_file(R)) {
  14213.      GGbarf(R,"Sorry, the GOPHER server won't let you see the file");
  14214.      rc = FALSE;
  14215.    }
  14216.    else {
  14217.  
  14218.    /* Dynamically allocate data set and use generated ddname.
  14219.     * Note that we have to allocate the data set name to a ddname and
  14220.     * then open the ddname to prevent C/370 from barfing on otherwise
  14221.     * valid data set names like those with hyphens in them.  But this
  14222.     * also lets us determine if the data set is sequential or a PDS.
  14223.     */
  14224.      strcpy(R->dsname,R->fileptr);
  14225.      dsntype = GGalloc(R->dsname,ddname,UNK,0);
  14226.      sprintf(R->buffer,"DD:%s",ddname);
  14227.      switch (dsntype) {
  14228.        case SEQ: rc = get_as_file(R); break;
  14229.        case PDS: rc = get_directory(R); break;
  14230.        default:
  14231.                printf("INVALID! requested:%s\n",R->fileptr);
  14232.                GGbarf(R,
  14233.                "Sorry, the GOPHER server couldn't allocate the file");
  14234.                rc = FALSE;
  14235.      }
  14236.    }
  14237.  }
  14238.  
  14239.  GGunalc(ddname);  /* free the ddname if set */
  14240.  
  14241.  return rc;
  14242.  
  14243. }
  14244.  
  14245. /*=================================================================*/
  14246.  
  14247. static Bool
  14248. get_the_info(RRECV *R, char *resource, char *plusptr)
  14249. {
  14250.  
  14251.  if (EQUAL(plusptr,"+") || EQUAL(plusptr,"+0")) {
  14252.    return get_info(R,resource);
  14253.  }
  14254.  else {
  14255.    GGbarf(R,
  14256.        "Sorry, there is no gopher+ support available for this item.");
  14257.    return FALSE;
  14258.  }
  14259. }
  14260.  
  14261. /*=================================================================*/
  14262.  
  14263. static Bool
  14264. get_adm_info(RRECV *R, char *resource, char *plusptr)
  14265. {
  14266.  
  14267.  GGbarf(R,
  14268.   "Sorry, there is no extended information available for this item.");
  14269.  return FALSE;
  14270. }
  14271.  
  14272. /*=================================================================*/
  14273.  
  14274. static Bool
  14275. get_dir_info(RRECV *R, char *resource, char *plusptr)
  14276. {
  14277.  
  14278.  GGbarf(R,
  14279.   "Sorry, there is no extended information available for this menu.");
  14280.  return FALSE;
  14281. }
  14282.  
  14283. /*=================================================================*/
  14284.  
  14285. /*******************************************************************/
  14286. /*   This routine Processes the file the user requested.           */
  14287. /*   If it's a menu, we'll form a menu line, if it's a             */
  14288. /*   file, we'll just send it as is.                               */
  14289. /*                                                                 */
  14290. /*   INPUT:   filename  pointer to the file name to open           */
  14291. /*            sockfd    socket descriptor for the client           */
  14292. /*                                                                 */
  14293. /*   OUTPUT:   print "gopher" lines.                               */
  14294. /*             TRUE  - file printed ok.                            */
  14295. /*             FALSE - Error reading or writing                    */
  14296. /*******************************************************************/
  14297.  
  14298. Bool
  14299. GGproc(RECV *R,
  14300.        int  in_local_mode
  14301.       )
  14302. {
  14303.  Bool              rc;            /* return value */
  14304.  char             *tabptr;
  14305.  char             *plusptr;
  14306.  char              resource[RBUFSIZE+1];
  14307.  
  14308.  /************/
  14309.  /*  First, strip off any "bad" characters from the arguments. */
  14310.  /************/
  14311.  
  14312.  /*
  14313.   * Break the argument up into one or two pieces delimited by tab.
  14314.   * Note that the tab is returned both by an index search item and
  14315.   * by a gopher+ item.  We have to assume that a client capable of
  14316.   * returning gopher+ items will never return a search string that
  14317.   * begins with one of the gopher+ characters.
  14318.   */
  14319.  
  14320.  R->gopherplus = NULL;
  14321.  
  14322.  R->fileptr = R->buffer;        /* filename passed in buffer */
  14323.  
  14324.  tabptr = strchr(R->fileptr,'\t');
  14325.  if (tabptr) {
  14326.    plusptr = tabptr + 1;
  14327.    switch (*plusptr) {
  14328.      case '+':
  14329.      case '!':
  14330.      case '$': R->gopherplus = (GOPHERPLUS *)R; /* temporary */
  14331.                break;
  14332.      default:  break;
  14333.    }
  14334.    *tabptr = '\0';
  14335.    R->fileptr = trim_leading_and_trailing_space(R->fileptr);
  14336.    R->wargptr = trim_leading_and_trailing_space(tabptr+1);
  14337.  }
  14338.  else {
  14339.    R->fileptr = trim_leading_and_trailing_space(R->fileptr);
  14340.    R->wargptr = NULL;
  14341.  }
  14342.  
  14343.  strncpy(resource,R->fileptr,sizeof(resource)-1);
  14344.  
  14345.  if (!*R->fileptr) {
  14346.    R->fileptr = DEFAULT_DIRECTORY;
  14347.  }
  14348.  
  14349.  /* If the *second* character of the path name is a "/", then
  14350.   * the first character is a gopher type.
  14351.   * If the first character of the path name is a "/", then
  14352.   * strip it off and punt with the rest of the file name.
  14353.   * If the first character is numeric, assume it's a gopher type.
  14354.   * Use the rest of the file name.
  14355.   * Otherwise, punt with the entire file name.
  14356.   */
  14357.  
  14358.  R->pathtype = '\0';
  14359.  
  14360.  if (strlen(R->fileptr) >= 2 && R->fileptr[1] == '/') {
  14361.    R->pathtype = R->fileptr[0];
  14362.    R->fileptr += 2;
  14363.  }
  14364.  else if (R->fileptr[0] == '/') {
  14365.    R->fileptr++;
  14366.  }
  14367.  else {
  14368.    switch (*R->fileptr) {
  14369.      case '0':
  14370.      case '1':
  14371.      case '2':
  14372.      case '3':
  14373.      case '4':
  14374.      case '5':
  14375.      case '6':
  14376.      case '7':
  14377.      case '8':
  14378.      case '9':  R->pathtype = R->fileptr[0]; R->fileptr++; break;
  14379.      default:   break;
  14380.    }
  14381.  }
  14382.  
  14383.  if (!R->outfp) printf("%s: requested:%s;\n",R->hostname,R->fileptr);
  14384.  
  14385.  (void)insure_my_name(R);  /* get host name now before we need it */
  14386.  
  14387.  if (R->gopherplus) {
  14388.    if (!R->outfp)
  14389.       printf("Responding to %s request for gopher+ %s<tab>%s\n",
  14390.              R->hostname,R->fileptr,plusptr);
  14391.    switch (*plusptr) {
  14392.      case '+':  rc = get_the_info(R,resource,plusptr);   break;
  14393.      case '!':  rc = get_adm_info(R,resource,plusptr);   break;
  14394.      case '$':  rc = get_dir_info(R,resource,plusptr);   break;
  14395.      default:   GGbarf(R,"Error, bad Gopher+ request");
  14396.                 rc = FALSE; break;
  14397.    }
  14398.  }
  14399.  else rc = get_info(R,resource);
  14400.  
  14401.  if (!rc) {
  14402.    fflush(stdout);
  14403.    fflush(stderr);
  14404.  }
  14405.  
  14406.  if (!in_local_mode) {
  14407.    (void)GGouts(R,NULL,NO_VALUE);      /* send terminating dot */
  14408.  }
  14409.  
  14410. #ifdef LOG_GOPHER_ACCESSES
  14411.  
  14412.  log_it(R,resource,rc);
  14413.  
  14414. #endif
  14415.  
  14416.  return rc;
  14417.  
  14418. }
  14419.  
  14420. ./ ADD NAME=GGREXX
  14421.  
  14422.  /********************************************************************/
  14423.  /*                                                                  */
  14424.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  14425.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  14426.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  14427.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  14428.  /*                                                                  */
  14429.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  14430.  /* including the implied warranties of merchantability and fitness, */
  14431.  /* are expressly denied.                                            */
  14432.  /*                                                                  */
  14433.  /* Provided this copyright notice is included, this software may    */
  14434.  /* be freely distributed and not offered for sale.                  */
  14435.  /*                                                                  */
  14436.  /* Changes or modifications may be made and used only by the maker  */
  14437.  /* of same, and not further distributed.  Such modifications should */
  14438.  /* be mailed to the author for consideration for addition to the    */
  14439.  /* software and incorporation in subsequent releases.               */
  14440.  /*                                                                  */
  14441.  /********************************************************************/
  14442.  
  14443. #pragma  csect(code,  "GG@REXX")
  14444. #pragma  csect(static,"GG$REXX")
  14445.  
  14446. #include "gg.h"
  14447. #include "ggrx.h"
  14448.  
  14449. #define NUMBER_OF_REXX_ARGS    2
  14450. #define DIE \
  14451.   GGbarf(R,"Sorry, the GOPHER server had a problem with the exec");\
  14452.   rexxrc = 999
  14453.  
  14454. /*===================================================================*/
  14455.  
  14456. /* Function invoked by gopher-close in GGproc. */
  14457.  
  14458. static void
  14459. rexx_close(RECV *R)
  14460. {
  14461.  GGCB          *gp = NULL;     /* for GETMAIN and FREEMAIN */
  14462.  
  14463.  GGtemp(R,R->temp,TEMP_CLOSE);
  14464.  GGtemp(R,R->temp,TEMP_REMOVE);
  14465.  FREEMAIN(R->temp, "REXX temp file struct");
  14466.  R->temp = NULL;
  14467.  
  14468.  return;
  14469. }
  14470.  
  14471. /*===================================================================*/
  14472.  
  14473. static void
  14474. load_function(Rexxfun *rfunp,
  14475.               char    *function_name)
  14476. {
  14477.  
  14478.  if (!*rfunp) {
  14479.    (*rfunp) = (Rexxfun)fetch(function_name);
  14480.    if (!*rfunp) fprintf(stderr,"Cannot fetch %s\n",function_name);
  14481.  }
  14482.  
  14483.  return;
  14484. }
  14485.  
  14486. /*===================================================================*/
  14487.  
  14488. static void
  14489. unload_function(Rexxfun *rfunp)
  14490. {
  14491.  
  14492.  if (*rfunp) {
  14493.    release((void (*)())(*rfunp));
  14494.    (*rfunp) = (Rexxfun)0;
  14495.  }
  14496.  
  14497.  return;
  14498. }
  14499.  
  14500. /*===================================================================*/
  14501.  
  14502. int
  14503. GGrexx(RECV *R,
  14504.        char *exectest,
  14505.        char *commandargs
  14506.       )
  14507. {
  14508.  GGCB              *gp = NULL;     /* for GETMAIN and FREEMAIN */
  14509.  unsigned int       bitflags;
  14510.  int                rexxrc = 0;
  14511.  int                irxexecrc;
  14512.  int                i;
  14513.  Rexxfun            irxexec;
  14514.  FILE              *fp;
  14515.  char               gopherargs[257];
  14516.  PARAMETER          parameter[11];
  14517.  struct execblock   execblk;
  14518.  struct {
  14519.          struct {
  14520.                  char   *argstring_ptr;
  14521.                  int     argstring_length;
  14522.                 }        argstring[NUMBER_OF_REXX_ARGS];
  14523.          int             argstring_end;
  14524.         }                arguments;
  14525.  
  14526.  GETMAIN(R->temp, struct tempfile, 1, "REXX temp file struct");
  14527.  if (!R->temp) {
  14528.    fprintf(stderr,"Cannot get a temp file struct\n");
  14529.    DIE;
  14530.  }
  14531.  
  14532.  irxexec = NULL;
  14533.  
  14534.  load_function(&irxexec,"IRXEXEC");
  14535.  if (!irxexec) {
  14536.    DIE;
  14537.  }
  14538.  
  14539.  /* old interface: allocate SYSTSPRT, run the exec, expecting it to
  14540.   * write to SYSTSPRT, then specify on return that the file SYSTSPRT
  14541.   * is to be read to get the gopher output.
  14542.   */
  14543.  
  14544.  /* new interface: allocate a new file, run the exec, expecting it
  14545.   * to write to that file, then specify on return that the file
  14546.   * is to be read to get the gopher output.
  14547.   */
  14548.  
  14549.  /* newer interface: run the exec, expecting it
  14550.   * to queue data to the data stack, then take each line on the
  14551.   * data stack and GGouts() it.  On return, no file.
  14552.   */
  14553.  
  14554.  /* Give the exec an empty SYSTSPRT file to write into.
  14555.   * Then when we read it we can see only what was added.
  14556.   * Since IRXEXEC doesn't close SYSTSPRT, we can't remove it
  14557.   * and reallocate it.
  14558.   */
  14559.  
  14560.  /* Create a temporary file. */
  14561.  
  14562.  CLEAR(R->temp);
  14563.  R->temp->crmode = CRLF;  /* for now, just assume non-binary */
  14564.  
  14565.  fp = GGtemp(R,R->temp,TEMP_CREATE);
  14566.  
  14567.  if (!fp) {
  14568.    printf("Cannot make a temporary file for REXX exec\n");
  14569.    DIE;
  14570.  }
  14571.  
  14572.  /* Open for write + close = clear it out */
  14573.  
  14574.  else if (fclose(fp) < 0) {
  14575.    printf("Cannot close temporary file for REXX exec\n");
  14576.    DIE;
  14577.  }
  14578.  
  14579.  if (rexxrc != 0) return rexxrc;
  14580.  
  14581.  /* Set up parameters for IRXEXEC:
  14582.   *
  14583.   * Param 1  -  address of EXECBLK
  14584.   * Param 2  -  address of arguments
  14585.   * Param 3  -  bitflags
  14586.   * Param 4  -  address of INSTBLK
  14587.   * Param 5  -  address of CPPL
  14588.   * Param 6  -  address of EVALBLOCK
  14589.   * Param 7  -  address of 8-byte work area
  14590.   * Param 8  -  address of user field
  14591.   * Param 9  -  address of environment block
  14592.   * Param 10 -  return code
  14593.   */
  14594.  
  14595.  /* set up exec block */
  14596.  
  14597.  CLEAR(&execblk);
  14598.  execblk.length = sizeof(execblk);
  14599.  memcpy (execblk.acryn, "IRXEXECB", 8);
  14600.  strncpy(execblk.member,exectest,8);
  14601.  for (i=0;i<8;i++) {
  14602.    if (execblk.member[i] == '\0')
  14603.        execblk.member[i] = ' ';
  14604.  }
  14605.  /* We may have just clobbered this, so do this after... */
  14606.  
  14607.  memcpy (execblk.ddname, REXX_EXEC_LIBRARY_DDNAME, 8);
  14608.  memcpy (execblk.subcom, REXX_EXEC_SUBCOM, 8);
  14609.  
  14610.  /* set up arguments  */
  14611.  
  14612.  sprintf(gopherargs,"OUTDD=%s;HOST=%s;PORT=%d;CLIENT=%s",
  14613.                     R->temp->ddname+3,
  14614.                     R->myname,
  14615.                     R->myport,
  14616.                     R->hostname);
  14617.  
  14618.  arguments.argstring[0].argstring_ptr    = commandargs;
  14619.  arguments.argstring[0].argstring_length = strlen(commandargs);
  14620.  arguments.argstring[1].argstring_ptr    = gopherargs;
  14621.  arguments.argstring[1].argstring_length = strlen(gopherargs);
  14622.  arguments.argstring_end                 = 0xffffffff;
  14623.  
  14624.  /* Invoke the rexx exec */
  14625.  
  14626.  bitflags = (unsigned int)(INVOKE_EXEC_AS_COMMAND +
  14627.                            RETURN_EXTENDED_RETURN_CODES);
  14628.  
  14629.  parameter[ 1] =   (PARAMETER)&execblk;
  14630.  parameter[ 2] =   (PARAMETER)&arguments;
  14631.  parameter[ 3] =   (PARAMETER)bitflags;
  14632.  parameter[ 4] =   (PARAMETER)NULL;  /* no INSTBLK */
  14633.  parameter[ 5] =   (PARAMETER)NULL;  /* no CPPL    */
  14634.  parameter[ 6] =   (PARAMETER)NULL;  /* no eval block */
  14635.  parameter[ 7] =   (PARAMETER)NULL;  /* no work area */
  14636.  parameter[ 8] =   (PARAMETER)NULL;  /* no user field, last parm */
  14637.  parameter[ 9] =   (PARAMETER)NULL;  /* no environment block */
  14638.  parameter[10] =   (PARAMETER)0;     /* return code */
  14639.  
  14640.  if (!R->outfp) {
  14641.    printf("Executing:%s %s\n", exectest, commandargs);
  14642.    printf("Gopherargs:%s\n",gopherargs);
  14643.  }
  14644.  
  14645.  irxexecrc = (*irxexec) (
  14646.                          ¶meter[1],
  14647.                          ¶meter[2],
  14648.                          ¶meter[3],
  14649.                          ¶meter[4],
  14650.                          ¶meter[5],
  14651.                          ¶meter[6],
  14652.                          ¶meter[7],
  14653.                          LASTPARM(¶meter[8]), /* old REXX */
  14654.                          ¶meter[9],
  14655.                          LASTPARM(¶meter[10]) /* new REXX */
  14656.                         );
  14657.  
  14658.  if (irxexecrc != 0) {
  14659.    fprintf(stderr,"Return code from IRXEXEC is %d\n", irxexecrc);
  14660.    rexxrc = irxexecrc;
  14661.  }
  14662.  else {
  14663.    rexxrc = parameter[10];
  14664.    strcpy(R->buffer,R->temp->ddname);
  14665.    R->fileptr = R->buffer;          /* Prepare for get-as-file */
  14666.    R->openfun  = NULL;
  14667.    R->readfun  = NULL;
  14668.    R->closefun = rexx_close;
  14669.  }
  14670.  
  14671.  unload_function(&irxexec);
  14672.  
  14673.  return rexxrc;
  14674.  
  14675. }
  14676.  
  14677. ./ ADD NAME=GGSERVE
  14678.  
  14679.  /********************************************************************/
  14680.  /*                                                                  */
  14681.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  14682.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  14683.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  14684.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  14685.  /*                                                                  */
  14686.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  14687.  /* including the implied warranties of merchantability and fitness, */
  14688.  /* are expressly denied.                                            */
  14689.  /*                                                                  */
  14690.  /* Provided this copyright notice is included, this software may    */
  14691.  /* be freely distributed and not offered for sale.                  */
  14692.  /*                                                                  */
  14693.  /* Changes or modifications may be made and used only by the maker  */
  14694.  /* of same, and not further distributed.  Such modifications should */
  14695.  /* be mailed to the author for consideration for addition to the    */
  14696.  /* software and incorporation in subsequent releases.               */
  14697.  /*                                                                  */
  14698.  /********************************************************************/
  14699.  
  14700. /*
  14701.  ***********************************************************************
  14702.  *                                                                     *
  14703.  * GOPHER server, based on the simple TCP/IP server from Shawn Hart at *
  14704.  * the University of Delaware.                                         *
  14705.  *                                                                     *
  14706.  ***********************************************************************
  14707.  *
  14708.  *  This server follows the GOPHER protocols defined by UMN.
  14709.  *  For more information, see the ANONYMOUS FTP site at
  14710.  *  BOOMBOX.MICRO.UMN.EDU.
  14711.  *
  14712.  ***********************************************************************
  14713.  *
  14714.  * November 1992 - parameters may be passed to the server:
  14715.  *
  14716.  * -d              run in debug mode
  14717.  *
  14718.  ***********************************************************************
  14719.  *
  14720.  * December 1992 - support for SNS/TCPAccess compilation
  14721.  *
  14722.  ***********************************************************************
  14723.  */
  14724.  
  14725. #pragma  csect(code,  "GG@SERVE")
  14726. #pragma  csect(static,"GG$SERVE")
  14727. #include "gg.h"
  14728.  
  14729. /********************************************************************/
  14730.  
  14731. static int
  14732. tcpsetup(int          port,
  14733.          int          qlen,
  14734.          int          mtftasks,
  14735.          FILE        *debugfp)
  14736. {
  14737.  int                  tinitrc;             /* loop counter*/
  14738.  int                  sockfd;              /* loop counter*/
  14739.  int                  x;                   /* loop counter*/
  14740.  struct linger        l;                   /* linger for setsockopt */
  14741.  struct sockaddr_in   server;          /*server address information */
  14742.  
  14743.  /*    initialize the MTF  environment.                   */
  14744.  
  14745.  if (debugfp) {
  14746.    fprintf(debugfp,"tinit...\n");
  14747.    fflush(debugfp);
  14748.  }
  14749.  
  14750.  tinitrc = tinit("GGSTASK", mtftasks);
  14751.  
  14752.  if (tinitrc != MTF_OK) {
  14753.    GGmtfer(tinitrc, "TINIT");
  14754.    return -1;
  14755.  }
  14756.  
  14757.  /*       open a TCP socket...                            */
  14758.  
  14759.  if (debugfp) {
  14760.    fprintf(debugfp,"socket...\n");
  14761.    fflush(debugfp);
  14762.  }
  14763.  
  14764.  if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  14765.    REPORT_TCP_ERROR("SOCKET - ");
  14766.    return -1;
  14767.  };
  14768.  
  14769.  /*  set the linger option on so we wait for data to be sent... */
  14770.  
  14771.  l.l_onoff  =  1;
  14772.  l.l_linger =100;           /* wait 100 seconds before giving up */
  14773.  
  14774.  if (debugfp) {
  14775.    fprintf(debugfp,"setsockopt (%d, SO_LINGER)...\n",sockfd);
  14776.    fflush(debugfp);
  14777.  }
  14778.  
  14779.  if (setsockopt(sockfd,SOL_SOCKET,SO_LINGER,(char *)&l,sizeof(l))
  14780.      < 0) {
  14781.    REPORT_TCP_ERROR("SETSOCKOPT - ");
  14782.    return -1;
  14783.  }
  14784.  
  14785.  /*    now bind our local address so that the client can send to us */
  14786.  
  14787.  memset((char *)&server, 0, sizeof(server));
  14788.  server.sin_family           =   AF_INET;
  14789.  server.sin_addr.s_addr      =   INADDR_ANY;
  14790.  server.sin_port             =   htons(port);
  14791.  
  14792.  if (debugfp) {
  14793.    fprintf(debugfp,"bind (%d)...\n",sockfd);
  14794.    fflush(debugfp);
  14795.  }
  14796.  
  14797.  if (Bind(sockfd, &server, sizeof(server)) < 0) {
  14798.    REPORT_TCP_ERROR("BIND - ");
  14799.    return -1;
  14800.  }
  14801.  
  14802.  /*    now set length of the connection queue... */
  14803.  
  14804.  if (debugfp) {
  14805.    fprintf(debugfp,"listen (sockfd=%d, qlen=%d)...\n",sockfd,qlen);
  14806.    fflush(debugfp);
  14807.  }
  14808.  
  14809.  if (listen(sockfd,qlen) != 0) {
  14810.    REPORT_TCP_ERROR("LISTEN -");
  14811.    return -1;
  14812.  }
  14813.  
  14814.  return sockfd;
  14815.  
  14816. }
  14817.  
  14818.  
  14819. /********************************************************************/
  14820. /*
  14821. *   This routine waits for an exception on the socket.  When one
  14822. *   occurs (by a subtask's "TAKESOCKET"!) we'll close our (the main
  14823. *   task's) connection to it.
  14824. *
  14825. *               INPUT   s   pointer to socket descripter.
  14826. *               OUTPUT  rc  -1 = connection timed out...
  14827. *                            0 = an excption occured!
  14828. */
  14829. /********************************************************************/
  14830.  
  14831. #ifdef SNSTCPIP
  14832.  
  14833. static int
  14834. closesock(int              newsockfd,
  14835.           int              timeout,
  14836.           FILE            *debugfp)
  14837. {
  14838.  if (debugfp) {
  14839.    fprintf(debugfp,"close (%d)...\n",newsockfd);
  14840.    fflush(debugfp);
  14841.  }
  14842.  
  14843.  if (close(newsockfd) < 0) REPORT_TCP_ERROR("CLOSE -");
  14844.  return 0;
  14845. }
  14846.  
  14847. #else
  14848.  
  14849. static int
  14850. closesock(int              newsockfd,
  14851.           int              timeout,
  14852.           FILE            *debugfp)
  14853. {
  14854.  int                       temps;
  14855.  struct sockaddr           clientaddress;
  14856.  int                       addrlen;
  14857.  int                       maxfdpl;
  14858.  struct fd_set             readmask;
  14859.  struct fd_set             writmask;
  14860.  struct fd_set             exepmask;
  14861.  int                       rc;
  14862.  struct timeval            time;
  14863.  
  14864.  temps = newsockfd;
  14865.  time.tv_sec = timeout;
  14866.  time.tv_usec = 0;
  14867.  maxfdpl = temps + 1;
  14868.  
  14869.  FD_ZERO(&readmask);
  14870.  FD_ZERO(&writmask);
  14871.  FD_ZERO(&exepmask);
  14872.  FD_SET(temps, &exepmask);
  14873.  
  14874.  if (debugfp) {
  14875.    fprintf(debugfp,"select (maxfdpl=%d)...\n",maxfdpl);
  14876.    fflush(debugfp);
  14877.  }
  14878.  
  14879.  rc = select(maxfdpl, &readmask, &writmask, &exepmask, &time);
  14880.  
  14881.  if (rc < 0) {
  14882.    REPORT_TCP_ERROR("SELECT - ");
  14883.    return rc;
  14884.  }
  14885.  else {
  14886.    if (rc == 0) fprintf(stdout,"The GIVESOCKET timed out!\n");
  14887.  
  14888.    if (debugfp) {
  14889.      fprintf(debugfp,"close (%d)...\n",newsockfd);
  14890.      fflush(debugfp);
  14891.    }
  14892.  
  14893.    if (close(newsockfd) < 0) REPORT_TCP_ERROR("CLOSE -");
  14894.    return rc;
  14895.  }
  14896. }
  14897.  
  14898. #endif
  14899.  
  14900. /********************************************************************/
  14901. /*
  14902. *       This routine starts a subtask, passing control of a socket
  14903. *       to it.  It then waits for the subtask to take the socket and
  14904. *       then closes the socket.
  14905. *
  14906. *       INPUT: newsockfd - socket descriptor to give to subtask.
  14907. */
  14908. /********************************************************************/
  14909.  
  14910. static Bool
  14911. spawn(
  14912.       int           newsockfd,
  14913.       int           timeout,
  14914.       RECV         *recvp,
  14915.       FILE         *debugfp)
  14916. {
  14917.  int                tschedrc;
  14918. #ifdef SNSTCPIP
  14919.  unsigned long      token;
  14920. #else
  14921.  struct clientid    clid;
  14922.  char               mysname[8];
  14923. #endif
  14924.  
  14925.  if (debugfp) {
  14926.    fprintf(debugfp,"getclientid...\n");
  14927.    fflush(debugfp);
  14928.  }
  14929.  
  14930. #ifdef SNSTCPIP
  14931.  
  14932.  token = closepass(newsockfd);
  14933.  if (debugfp) {
  14934.    fprintf(debugfp,"token = %X\n",token);
  14935.    fflush(debugfp);
  14936.  }
  14937.  
  14938. #else
  14939.  
  14940.  memset(&clid,0,sizeof(clid));
  14941.  if(getclientid(AF_INET,&clid) < 0) {
  14942.    REPORT_TCP_ERROR("GETCLIENTID");
  14943.    return FALSE;
  14944.  }
  14945.  
  14946.  if (debugfp) {
  14947.    fprintf(debugfp,"client name = %8.8s, subtaskname = %8.8s\n",
  14948.                    clid.name, clid.subtaskname);
  14949.    fflush(debugfp);
  14950.  }
  14951.  
  14952.  clid.domain = AF_INET;
  14953.  memcpy(mysname,clid.subtaskname,8);
  14954.  memcpy(clid.subtaskname,"        ",8);
  14955.  
  14956.  if (debugfp) {
  14957.    fprintf(debugfp,"givesocket (%d)...\n",newsockfd);
  14958.    fflush(debugfp);
  14959.  }
  14960.  
  14961.  if(givesocket(newsockfd,&clid) != 0) {
  14962.    REPORT_TCP_ERROR("GIVESOCKET");
  14963.    return FALSE;
  14964.  }
  14965.  memcpy(clid.subtaskname,mysname,8);
  14966.  
  14967.  if (debugfp) {
  14968.    fprintf(debugfp,"client name = %8.8s, subtaskname = %8.8s\n",
  14969.                    clid.name, clid.subtaskname);
  14970.    fflush(debugfp);
  14971.  }
  14972.  
  14973. #endif
  14974.  
  14975.  if (debugfp) {
  14976.    fprintf(debugfp,"tsched...\n");
  14977.    fflush(debugfp);
  14978.  }
  14979.  
  14980.  tschedrc = tsched(MTF_ANY,"GGSRECV",
  14981. #ifdef SNSTCPIP
  14982.                            token,
  14983. #else
  14984.                            newsockfd,
  14985.                            clid,
  14986. #endif
  14987.                            recvp,
  14988.                            (debugfp ? 1 : 0));
  14989.  
  14990.  if (debugfp) {
  14991.    fprintf(debugfp,"tsched completed...rc=%d\n",tschedrc);
  14992.    fflush(debugfp);
  14993.  }
  14994.  
  14995.  if (tschedrc != 0) {
  14996.    GGmtfer(tschedrc,"TSCHED");
  14997.    return FALSE;
  14998.  }
  14999.  
  15000.  if (closesock(newsockfd,timeout,debugfp) < 0) {
  15001.    REPORT_TCP_ERROR("close socket");
  15002.    return FALSE;
  15003.  }
  15004.  
  15005.  return TRUE;
  15006.  
  15007. }
  15008.  
  15009. /******************************************************************/
  15010.  
  15011. static Bool
  15012. numparm(
  15013.         char *pvar,
  15014.         char *pval,
  15015.         int  *ivalp
  15016.        )
  15017. {
  15018.  if (*(pval + strspn(pval,"0123456789"))) {
  15019.    fprintf(stdout,"Non-numeric value given for %s: %s\n",
  15020.                   pvar, pval);
  15021.    return FALSE;
  15022.  }
  15023.  else {
  15024.   *ivalp = atoi(pval);
  15025.   return TRUE;
  15026.  }
  15027. }
  15028.  
  15029. /******************************************************************/
  15030.  
  15031. int
  15032. main(int            argc,
  15033.          char     **argv)
  15034. {
  15035.  int                trc;               /* return code */
  15036.  int                x;                 /* loop counter*/
  15037.  int                sockfd;            /* connection socket...*/
  15038.  int                newsockfd;         /* new connection socket...*/
  15039.  int                clientlen;         /* new connection socket...*/
  15040.  int                i;
  15041.  int                n;
  15042.  int                ival;
  15043.  char               cval;
  15044.  char              *p;
  15045.  char              *cp;
  15046.  FILE              *debugfp;
  15047.  FILE              *pfp;
  15048.  struct sockaddr_in client;            /* client address information */
  15049. #ifndef SNSTCPIP
  15050.  struct clientid    clid;              /* client info for givesocket */
  15051. #endif
  15052.  RECV               recvtemplate;
  15053.  int                mtftasks;
  15054.  int                port;
  15055.  int                qlength;
  15056.  int                timeout;
  15057.  char               telnet   [257];
  15058.  char               bookmgr  [257];
  15059.  char               domain   [257];
  15060.  char               pline    [RBUFSIZE];
  15061.  char               pvar     [RBUFSIZE];
  15062.  char               pval     [RBUFSIZE];
  15063.  char               buffer   [255];      /* buffer for input/output*/
  15064.  
  15065. /******************************************************************/
  15066. /* Set parameter defaults.                                        */
  15067. /******************************************************************/
  15068.  
  15069.  mtftasks     = MTF_TASKS;
  15070.  port         = SERV_TCP_PORT;
  15071.  qlength      = TCP_QUEUE_LENGTH;
  15072.  timeout      = CONNECT_TIME_OUT;
  15073.  COPY(telnet,   TELNET_COMMAND_NAME);
  15074.  COPY(bookmgr,  BOOKMGR_COMMAND_NAME);
  15075.  COPY(domain,   MY_DOMAIN_SUFFIX);
  15076.  
  15077. /******************************************************************/
  15078. /* Process server parameters.                                     */
  15079. /******************************************************************/
  15080.  
  15081.  debugfp = NULL;
  15082.  
  15083.  for (i = 1; i < argc; i++) {
  15084.    p = argv[i];
  15085.    if (*p == '-') {
  15086.      while (*++p) {
  15087.        switch (toupper(*p)) {
  15088.          case 'D':  debugfp = fopen(DEBUG_FILE,"w");
  15089.                     break;
  15090.          default:   break;
  15091.        }
  15092.      }
  15093.    }
  15094.  }
  15095.  
  15096. /******************************************************************/
  15097. /*         Read startup parameters from parameter file.           */
  15098. /******************************************************************/
  15099.  
  15100. /*
  15101.  * If dd:GGPARMS is present, then read parameters therefrom.
  15102.  * If not, then use defaults.  In any case, defaults will be
  15103.  * assigned where a corresponding parameter file line isn't found,
  15104.  *
  15105.  * Syntax of parameter file lines:
  15106.  *
  15107.  * VARIABLE value   comments
  15108.  *
  15109.  * e.g.
  15110.  *
  15111.  * MTFTASKS    8    the number of tasks
  15112.  *
  15113.  * Comments are indicated by "!" in col 1.
  15114.  *
  15115.  */
  15116.  
  15117.  pfp = fopen(PARAMETER_FILE,"r");
  15118.  if (!pfp) {
  15119.    perror(PARAMETER_FILE);
  15120.    fprintf(stdout,
  15121.            "No parameter file.  Using all installed defaults.\n");
  15122.    fflush(stderr);
  15123.  }
  15124.  else {
  15125.    for (;;) {
  15126.      fgets(pline, sizeof(pline), pfp);
  15127.      if (ferror(pfp)) {
  15128.        fprintf(stderr,"Error reading parameters from %s\n",
  15129.                       PARAMETER_FILE);
  15130.        fflush(stderr);
  15131.        break;
  15132.      }
  15133.      if (feof(pfp)) break;
  15134.      cp = pline;                     /* Start parameter scan       */
  15135.      if (*cp == '!') continue;       /* Skip comment               */
  15136.      *pvar = '\0';                   /* Clear parameter variable   */
  15137.      sscanf(cp,"%s %n",pvar,&n);     /* Get parameter, bump scan   */
  15138.      if (!*pvar) continue;           /* If nothing on line, skip   */
  15139.      uppercase_in_place(pvar);       /* Fold variable name         */
  15140.      cp += n;                        /* Bump to next word in file  */
  15141.      *pval = '\0';                   /* Clear parameter value      */
  15142.      sscanf(cp,"%s %n",pval,&n);     /* Get next word, bump scan   */
  15143.      if (!*pval) {
  15144.        fprintf(stdout,"Parameter error: value missing for %s\n",
  15145.                       pvar);
  15146.        continue;
  15147.      }
  15148.      fprintf(stderr,"Setting %s to '%s' (%d)\n",pvar,pval,ival);
  15149.      if      (EQUAL(pvar,"MTFTASKS" )) {
  15150.                                         if (numparm(pvar,pval,&ival))
  15151.                                            mtftasks = ival;
  15152.                                        }
  15153.      else if (EQUAL(pvar,"PORT"     )) {
  15154.                                         if (numparm(pvar,pval,&ival))
  15155.                                            port     = ival;
  15156.                                        }
  15157.      else if (EQUAL(pvar,"QLENGTH"  )) {
  15158.                                         if (numparm(pvar,pval,&ival))
  15159.                                            qlength  = ival;
  15160.                                        }
  15161.      else if (EQUAL(pvar,"TIMEOUT"  )) {
  15162.                                         if (numparm(pvar,pval,&ival))
  15163.                                            timeout  = ival;
  15164.                                        }
  15165.      else if (EQUAL(pvar,"TELNET"   )) {
  15166.                                         uppercase_in_place(pval);
  15167.                                         COPY(telnet,pval);
  15168.                                        }
  15169.      else if (EQUAL(pvar,"BOOKMGR"  )) {
  15170.                                         uppercase_in_place(pval);
  15171.                                         COPY(bookmgr,pval);
  15172.                                        }
  15173.      else if (EQUAL(pvar,"DOMAIN"   )) {
  15174.                                         uppercase_in_place(pval);
  15175.                                         COPY(domain,pval);
  15176.                                        }
  15177.      else {
  15178.        fprintf(stdout,"Unknown parameter, %s.  Skipping.\n",pvar);
  15179.      }
  15180.    }
  15181.    (void)fclose(pfp);
  15182.  }
  15183.  
  15184. /******************************************************************/
  15185. /*         display parameter values in effect                     */
  15186. /******************************************************************/
  15187.  
  15188.  /* Set defaults to pass to the subtask. */
  15189.  
  15190.  CLEAR(&recvtemplate);
  15191.  
  15192.  recvtemplate.myport       = port;
  15193.  recvtemplate.mytelnet     = telnet;
  15194.  recvtemplate.mybkmgr      = bookmgr;
  15195.  recvtemplate.mydomain     = domain;
  15196.  recvtemplate.accvector    = NULL; /* set when access table loaded */
  15197.  
  15198.  fprintf(stdout,"Parameter values in effect:\n\n");
  15199.  fprintf(stdout,"MTFTASKS = %d\n", mtftasks);
  15200.  fprintf(stdout,"QLENGTH  = %d\n", qlength);
  15201.  fprintf(stdout,"TIMEOUT  = %d\n", timeout);
  15202.  fprintf(stdout,"PORT     = %d\n", recvtemplate.myport);
  15203.  fprintf(stdout,"TELNET   = %s\n", recvtemplate.mytelnet);
  15204.  fprintf(stdout,"BOOKMGR  = %s\n", recvtemplate.mybkmgr);
  15205.  fprintf(stdout,"DOMAIN   = %s\n", recvtemplate.mydomain);
  15206.  fprintf(stdout,"\n");
  15207.  
  15208.  fflush(stdout);
  15209.  
  15210. /******************************************************************/
  15211. /*         load the access table                                  */
  15212. /******************************************************************/
  15213.  
  15214.  if (!GGacces(&recvtemplate,ACCESS_LOAD)) {
  15215.    fprintf(stdout,"Could not load the access table!\n");
  15216.    exit(16);
  15217.  }
  15218.  
  15219. /******************************************************************/
  15220. /*         set up the connection to the socket...                 */
  15221. /******************************************************************/
  15222.  
  15223.  sockfd = tcpsetup(port,qlength,mtftasks,debugfp);
  15224.  if (sockfd < 0) {
  15225.    fprintf(stdout,"Could not set up the TCP/IP environment!\n");
  15226.    exit(16);
  15227.  }
  15228.  
  15229. /******************************************************************/
  15230. /*         Now loop, waiting for a connection request.            */
  15231. /******************************************************************/
  15232.  
  15233.  clientlen = sizeof(client);
  15234.  x = 0;
  15235.  for (;;) {
  15236.  
  15237.    if (debugfp) {
  15238.      fprintf(debugfp,"accept (%d)...\n",sockfd);
  15239.      fflush(debugfp);
  15240.    }
  15241.  
  15242.    if ((newsockfd=Accept(sockfd,&client,&clientlen)) == -1) {
  15243.      REPORT_TCP_ERROR("ACCEPT - ");
  15244.      exit(8);
  15245.    }
  15246.    if (debugfp) {
  15247.      fprintf(debugfp,"newsockfd=%d...\n",newsockfd);
  15248.      fflush(debugfp);
  15249.    }
  15250.  
  15251.    x++;
  15252.    if (!spawn(newsockfd,timeout,&recvtemplate,debugfp)) {
  15253.      fprintf(stdout,"spawn failed for socket %d\n",newsockfd);
  15254.      exit(8);
  15255.    }
  15256.    else {
  15257.      if (debugfp) {
  15258.        fprintf(debugfp,"spawn OK for socket %d\n",newsockfd);
  15259.        fflush(debugfp);
  15260.      }
  15261.    }
  15262.  }
  15263.  
  15264. /******************************************************************/
  15265. /*         Wait for all pending tasks to complete (should never   */
  15266. /*         run, since I haven't added PURGE support yet...)       */
  15267. /*         then shut down subtasks.                               */
  15268. /******************************************************************/
  15269.  
  15270.  if (debugfp) {
  15271.    fprintf(debugfp,"tsyncro...\n");
  15272.    fflush(debugfp);
  15273.  }
  15274.  
  15275.  trc = tsyncro(MTF_ALL);
  15276.  if (trc != 0) {
  15277.    GGmtfer(trc,"TSYNCRO");
  15278.  }
  15279.  
  15280.  if (debugfp) {
  15281.    fprintf(debugfp,"tterm...\n");
  15282.    fflush(debugfp);
  15283.  }
  15284.  
  15285.  trc = tterm();
  15286.  if (trc != 4) {
  15287.    GGmtfer(trc,"TTERM");
  15288.    exit(8);
  15289.  }
  15290.  
  15291.  (void)GGacces(&recvtemplate,ACCESS_FREE);  /* free access table */
  15292.  
  15293.  if (debugfp) fclose(debugfp);
  15294.  
  15295.  exit(0);
  15296.  
  15297. }
  15298. ./ ADD NAME=GGSLEEP
  15299.  
  15300.  /********************************************************************/
  15301.  /*                                                                  */
  15302.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  15303.  /*                                                                  */
  15304.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  15305.  /* including the implied warranties of merchantability and fitness, */
  15306.  /* are expressly denied.                                            */
  15307.  /*                                                                  */
  15308.  /* Provided this copyright notice is included, this software may    */
  15309.  /* be freely distributed and not offered for sale.                  */
  15310.  /*                                                                  */
  15311.  /* Changes or modifications may be made and used only by the maker  */
  15312.  /* of same, and not further distributed.  Such modifications should */
  15313.  /* be mailed to the author for consideration for addition to the    */
  15314.  /* software and incorporation in subsequent releases.               */
  15315.  /*                                                                  */
  15316.  /********************************************************************/
  15317.  
  15318. #pragma  csect(code,  "GG@SLEEP")
  15319. #pragma  csect(static,"GG$SLEEP")
  15320.  
  15321. #include "gg.h"
  15322. #include "ggsvc.h"
  15323.  
  15324. #define STIMER_SVC     47
  15325.  
  15326. int
  15327. GGsleep(int    seconds)
  15328. {
  15329.  int           hundredths_of_a_second;
  15330.  SVC_REGISTER  reg15;
  15331.  SVC_REGISTER  reg0;
  15332.  SVC_REGISTER  reg1;
  15333.  
  15334.  hundredths_of_a_second = seconds * 100;
  15335.  
  15336.  reg15 = (SVC_REGISTER) 0;
  15337.  reg0  = (SVC_REGISTER) 0x91000000;
  15338.  reg1  = (SVC_REGISTER) &hundredths_of_a_second;
  15339.  
  15340.  SVC(STIMER_SVC,®15,®0,®1);
  15341.  
  15342.  return (int)reg15;
  15343.  
  15344. }
  15345.  
  15346. ./ ADD NAME=GGSOCKT
  15347.  
  15348.  /********************************************************************/
  15349.  /*                                                                  */
  15350.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  15351.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  15352.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  15353.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  15354.  /*                                                                  */
  15355.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  15356.  /* including the implied warranties of merchantability and fitness, */
  15357.  /* are expressly denied.                                            */
  15358.  /*                                                                  */
  15359.  /* Provided this copyright notice is included, this software may    */
  15360.  /* be freely distributed and not offered for sale.                  */
  15361.  /*                                                                  */
  15362.  /* Changes or modifications may be made and used only by the maker  */
  15363.  /* of same, and not further distributed.  Such modifications should */
  15364.  /* be mailed to the author for consideration for addition to the    */
  15365.  /* software and incorporation in subsequent releases.               */
  15366.  /*                                                                  */
  15367.  /********************************************************************/
  15368.  
  15369. #pragma  csect(code,  "GG@SOCKT")
  15370. #pragma  csect(static,"GG$SOCKT")
  15371. #include "gg.h"
  15372.  
  15373. /****** Output one data line for the server. *************************/
  15374.  
  15375. Bool
  15376. GGsockt(gp,sp)
  15377. RGGCB  *gp;
  15378. RCONN  *sp;
  15379. {
  15380.  RECV  *R;
  15381.  char  *s_buf;
  15382.  int    gopher_bytes;
  15383.  int    writrc;
  15384.  Bool   procok;
  15385.  
  15386.  /* Before sending a request to the server, do a cleanup operation
  15387.   * to make sure that no more responses are coming from the server.
  15388.   * This is done by GGservr here, but it is now done outside so that
  15389.   * the FTP gateway can call this routine without linkind it in.
  15390.   *
  15391.   *  GGesrvr(gp,sp);           -- End server read --
  15392.   *
  15393.   */
  15394.  
  15395.  /* If local mode, call server subtask processor with command. */
  15396.  
  15397.  if (gp && (R=gp->recvp) && !sp->is_ftp) {
  15398.    if (!R->outfp) {
  15399.      CRIT1("Can't send data locally, non-socket not connected");
  15400.      return FALSE;
  15401.    }
  15402.    strncpy(R->buffer, gp->gopher_command, sizeof(R->buffer)-1);
  15403.    strcpy(R->myname, LOCAL_HOST_FROB);  /* used by PDS feature */
  15404.  
  15405.    /* allocate SYSTSPRT file, used by REXX EXEC interface */
  15406.  
  15407.    if (GGtso(
  15408.      "ALLOC FI(SYSTSPRT) T SP(100 100) REL REU DEL"
  15409.      " RECFM(V B) LRECL(1024) BLKSIZE(32760)"
  15410.              ) != 0) {
  15411.      fprintf(stderr,
  15412.        "Warning: Cannot allocate temporary SYSTSPRT file.\n");
  15413.      fprintf(stderr,
  15414.        "         Some interfaces may not work properly.\n");
  15415.    }
  15416.  
  15417.    procok = GGproc(R,TRUE);
  15418.  
  15419.    /* free SYSTSPRT file, used by REXX EXEC interface */
  15420.  
  15421.    (void)GGunalc("SYSTSPRT");
  15422.  
  15423.    /* Prepare to read from the beginning of the file */
  15424.  
  15425.    if (fseek(R->outfp, 0, SEEK_SET) != 0) {
  15426.      CRIT1("Can't reposition to start of local file");
  15427.      return FALSE;
  15428.    }
  15429.    return TRUE;   /* used to return procok but want to see barfs */
  15430.  }
  15431.  
  15432.  if (gp) {
  15433.    gopher_bytes = strlen(gp->gopher_command);
  15434.    memcpy(sp->client_buf,gp->gopher_command,gopher_bytes);
  15435.  }
  15436.  else {
  15437.    gopher_bytes = strlen(sp->client_buf);
  15438.  }
  15439.  
  15440.  sp->client_buf[gopher_bytes]   = CARRIAGE_RETURN;
  15441.  sp->client_buf[gopher_bytes+1] = LINE_FEED;
  15442.  
  15443.  if (!sp->is_ftp        &&
  15444.      sp->receiving_text &&
  15445.      gopher_bytes == 1  &&
  15446.      sp->client_buf[0] == '.') {
  15447.    sp->receiving_text = FALSE;
  15448.  }
  15449.  
  15450.  if (gp && gp->debug_mode)
  15451.     GGdump(gp,"Writing to server",sp->client_buf,gopher_bytes+2);
  15452.  
  15453.  EBCDIC_TO_ASCII(sp->client_buf,gopher_bytes+2);
  15454.  
  15455.  writrc = write(sp->ns, sp->client_buf, gopher_bytes+2);
  15456.  if (writrc < 0) {
  15457.    sp->connection_broken = TRUE;
  15458.    if (gp) {
  15459.      CRIT2("TCP/IP error: write() failed to send data to server %s.",
  15460.            gp->ggserver);
  15461.    }
  15462.    else {
  15463.      fprintf(stderr,
  15464.              "TCP/IP error: write() failed to send data to server %s.",
  15465.              sp->server_hostname);
  15466.    }
  15467.    return FALSE;
  15468.  }
  15469.  
  15470.  if (sp->is_ftp) return TRUE;
  15471.  
  15472.  /* Prepare server for read. */
  15473.  
  15474.  sp->server_has_nothing       = FALSE;
  15475.  sp->server_finished_replying = FALSE;
  15476.  sp->sending_text             = FALSE;
  15477.  sp->dont_read                = FALSE;
  15478.  
  15479.  ISPF("CONTROL DISPLAY LOCK");
  15480.  ISPF("DISPLAY PANEL(GGMLSOCK)");
  15481.  
  15482.  return TRUE;
  15483. }
  15484.  
  15485. ./ ADD NAME=GGSOPT
  15486.  
  15487.  /********************************************************************/
  15488.  /*                                                                  */
  15489.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  15490.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  15491.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  15492.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  15493.  /*                                                                  */
  15494.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  15495.  /* including the implied warranties of merchantability and fitness, */
  15496.  /* are expressly denied.                                            */
  15497.  /*                                                                  */
  15498.  /* Provided this copyright notice is included, this software may    */
  15499.  /* be freely distributed and not offered for sale.                  */
  15500.  /*                                                                  */
  15501.  /* Changes or modifications may be made and used only by the maker  */
  15502.  /* of same, and not further distributed.  Such modifications should */
  15503.  /* be mailed to the author for consideration for addition to the    */
  15504.  /* software and incorporation in subsequent releases.               */
  15505.  /*                                                                  */
  15506.  /********************************************************************/
  15507.  
  15508. #pragma  csect(code,  "GG@SOPT ")
  15509. #pragma  csect(static,"GG$SOPT ")
  15510. #include "gg.h"
  15511.  
  15512. #define BOOLOPTSET(A,B,C) \
  15513.    switch (A[0]) { \
  15514.      case  'n': \
  15515.      case  'N':   B = FALSE; break; \
  15516.      case  'y': \
  15517.      case  'Y':   B = TRUE; break; \
  15518.      case '\0': \
  15519.      default:     B = C; break; \
  15520.    }
  15521.  
  15522. /****** Set options that are stored in ISPF profile. *****************/
  15523.  
  15524. void
  15525. GGsopt(gp,which)
  15526. RGGCB *gp;
  15527. OPTION which;
  15528. {
  15529.  int   arrows;
  15530.  char  ggextpow [  4];
  15531.  char  ggextpap [  4];
  15532.  char  ggscroll [  4];
  15533.  char  ggcursor [  4];
  15534.  
  15535.  if (which == OPTION_ALL) {
  15536.    ISPF("VGET (GGEXTPOW GGEXTPAP GGSCROLL GGCURSOR) PROFILE");
  15537.  }
  15538.  
  15539.  if (which == OPTION_ALL || which == OPTION_OTHER) {
  15540.    VGET("GGEXTPOW ", ggextpow);
  15541.    VGET("GGEXTPAP ", ggextpap);
  15542.    BOOLOPTSET(ggextpow, gp->warn_overwrite, TRUE);
  15543.    BOOLOPTSET(ggextpap, gp->warn_append,    TRUE);
  15544.  }
  15545.  
  15546.  if (which == OPTION_ALL || which == OPTION_VIEW) {
  15547.    VGET("GGSCROLL ", ggscroll);
  15548.    VGET("GGCURSOR ", ggcursor);
  15549.    BOOLOPTSET(ggscroll, gp->autoscroll, TRUE);
  15550.    BOOLOPTSET(ggcursor, gp->autocursor, FALSE);
  15551.  }
  15552.  
  15553.  return;
  15554. }
  15555.  
  15556. ./ ADD NAME=GGSTASK
  15557.  
  15558.  /********************************************************************/
  15559.  /*                                                                  */
  15560.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  15561.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  15562.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  15563.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  15564.  /*                                                                  */
  15565.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  15566.  /* including the implied warranties of merchantability and fitness, */
  15567.  /* are expressly denied.                                            */
  15568.  /*                                                                  */
  15569.  /* Provided this copyright notice is included, this software may    */
  15570.  /* be freely distributed and not offered for sale.                  */
  15571.  /*                                                                  */
  15572.  /* Changes or modifications may be made and used only by the maker  */
  15573.  /* of same, and not further distributed.  Such modifications should */
  15574.  /* be mailed to the author for consideration for addition to the    */
  15575.  /* software and incorporation in subsequent releases.               */
  15576.  /*                                                                  */
  15577.  /********************************************************************/
  15578.  
  15579. #pragma  csect(code,  "GGSTASK ")
  15580. #pragma  csect(static,"GG$TASK ")
  15581. #include "gg.h"
  15582.  
  15583. /*=================================================================*/
  15584.  
  15585. /*******************************************************************/
  15586. /*                                                                 */
  15587. /*    this is a debugging routine;  it looks at the status of a    */
  15588. /*    socket.                                                      */
  15589. /*******************************************************************/
  15590.  
  15591. static void
  15592. lookatsocket(int sockfd)
  15593. {
  15594.  int             rc;                       /* return code */
  15595.  int             length;                   /* length variable */
  15596.  int             option;
  15597.  int             x;
  15598.  struct linger   l;                        /* linger structure */
  15599.  char            buffer[RBUFSIZE];
  15600.  
  15601.  length = sizeof(l);
  15602.  if (Getsockopt(sockfd,SOL_SOCKET, SO_LINGER,&l,&length)==0) {
  15603.    printf("l_onoff=%d\n",l.l_onoff);
  15604.    printf("l_linger=%d\n",l.l_linger);
  15605.  }
  15606.  else REPORT_TCP_ERROR("GETSOCKOPT");
  15607.  
  15608.  length = sizeof(option);
  15609.  if (Getsockopt(sockfd,SOL_SOCKET, SO_ERROR,&option,&length)==0) {
  15610.    printf("so_error=%d\n",option);
  15611.  }
  15612.  else REPORT_TCP_ERROR("GETSOCKOPT");
  15613.  
  15614.  if (fcntl(sockfd,F_SETFL,FNDELAY)!=0) REPORT_TCP_ERROR("FCNTL");
  15615.  
  15616.  length = recv(sockfd,buffer,sizeof(buffer)-1,0);
  15617.  if (length == -1) {
  15618.    if (errno != EWOULDBLOCK) REPORT_TCP_ERROR("recv");
  15619.  }
  15620.  else {
  15621.    buffer[sizeof(buffer)-1] = 0;
  15622.    printf("buffer =%s\n",buffer);
  15623.    for (x=0;x<length;x++) printf("%x ",buffer[x]);
  15624.    printf("\n");
  15625.  }
  15626.  
  15627. }
  15628.  
  15629. /*******************************************************************/
  15630.  
  15631. /**************************************************************/
  15632. /*    this routine processes the data once a connection       */
  15633. /*    has been accepted.  It just takes the data sent by the  */
  15634. /*    client and prints it to sysprint, then sends it back    */
  15635. /*    to the client.                                          */
  15636. /*                                                            */
  15637. /*             INPUT:   newsockfd  - socket descriptor        */
  15638. /*                      clid       - takesocket structure...  */
  15639. /**************************************************************/
  15640.  
  15641. void
  15642. GGSrecv(
  15643. #ifdef SNSTCPIP
  15644.  unsigned long      token,
  15645. #else
  15646.  int                newsockfd,
  15647.  struct clientid    clid,
  15648. #endif
  15649.  RECV              *recvtp,
  15650.  int                is_debug
  15651.        )
  15652. {
  15653.  RECV              *R;
  15654.  struct hostent    *hostentp;
  15655.  char              *bufptr;   /* pointer into buffer strings         */
  15656.  char              *cp;
  15657.  char              *hp;
  15658.  char             **halias;
  15659.  struct tm         *tmp;
  15660.  int                retcode;  /* return code                         */
  15661.  int                len;      /* length of the buffer we're sent     */
  15662.  int                addrlen;  /* length of client address socket     */
  15663.  int                hostlen;
  15664.  int                domslen;
  15665.  int                buflen;
  15666.  time_t             timeval;
  15667.  struct sockaddr_in clientaddress; /* address of client              */
  15668.  RECV               r;
  15669.  char               outbuf[RBUFSIZE];  /* hold an output string */
  15670.  char               echobuf[RBUFSIZE];
  15671.  char               timestamp[20];
  15672.  
  15673.  /* Initialize recv struct with values passed from main task. */
  15674.  
  15675.  R = &r;
  15676.  memcpy(R, recvtp, sizeof(RECV));
  15677.  
  15678. #ifdef SNSTCPIP
  15679.  
  15680.  if (is_debug) {
  15681.    fprintf(stdout,"openold (token=%X)...\n",token);
  15682.    fflush(stdout);
  15683.  }
  15684.  s0skcfg.exitfunc = NULL; /* Set exit address to NULL */
  15685.  R->sockfd = openold(token);
  15686.  if (is_debug) {
  15687.    fprintf(stdout,"sockfd from openold is %d\n", R->sockfd);
  15688.    fflush(stdout);
  15689.  }
  15690.  if(R->sockfd < 0) {
  15691.    REPORT_TCP_ERROR("OPENOLD");
  15692.    fflush(stderr);
  15693.    return;
  15694.  }
  15695.  
  15696. #else
  15697.  
  15698.  if (is_debug) {
  15699.    fprintf(stdout,"takesocket (newsockfd=%d)...\n",newsockfd);
  15700.    fprintf(stdout,"name is %8.8s, subtaskname is %8.8s\n",
  15701.                   clid.name,clid.subtaskname);
  15702.    fflush(stdout);
  15703.  }
  15704.  
  15705.  R->sockfd = takesocket(&clid,newsockfd);
  15706.  if (is_debug) {
  15707.    fprintf(stdout,"sockfd from takesocket is %d\n", R->sockfd);
  15708.    fflush(stdout);
  15709.  }
  15710.  if(R->sockfd < 0) {
  15711.    REPORT_TCP_ERROR("TAKESOCKET");
  15712.    return;
  15713.  }
  15714.  
  15715. #endif
  15716.  
  15717.  time(&timeval);
  15718.  tmp = localtime(&timeval);
  15719.  sprintf(timestamp,"%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d",
  15720.          tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_year,
  15721.          tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
  15722.  
  15723.  if (is_debug) {
  15724.    fprintf(stdout,"getpeername...\n");
  15725.    fflush(stdout);
  15726.  }
  15727.  
  15728.  addrlen = sizeof(clientaddress);
  15729.  if(Getpeername(R->sockfd,&clientaddress,&addrlen)!=0) {
  15730.    REPORT_TCP_ERROR("GETPEERNAME");
  15731.    printf("could not determine client address for socket %d\n",
  15732.           R->sockfd);
  15733.  }
  15734.  
  15735.  /* Try to get the name of the client host.
  15736.   * First initialize the hostname to a printable representation of
  15737.   * the IP address in case we can't get a hostname.
  15738.   * We use curlies instead of the traditional squares because of
  15739.   * the ancient 3270's that will be displaying this stuff.
  15740.   */
  15741.  
  15742.  strcpy(R->hostname,"{");
  15743.  SPRINTF_IP_ADDRESS(R->hostname+1, clientaddress.sin_addr);
  15744.  strcat(R->hostname,"}");
  15745.  
  15746.  if (is_debug) {
  15747.    fprintf(stdout,"gethostbyaddr...\n");
  15748.    fflush(stdout);
  15749.  }
  15750.  
  15751.  hostentp = Gethostbyaddr(&clientaddress.sin_addr,
  15752.                           sizeof(clientaddress.sin_addr),
  15753.                           AF_INET);
  15754.  
  15755.  if (hostentp && hostentp->h_name) {
  15756.    memcpy(&R->clienthostent, hostentp, sizeof(struct hostent));
  15757.    strcpy(R->hostname,hostentp->h_name);
  15758.    uppercase_in_place(R->hostname);
  15759.  }
  15760.  
  15761.  strcpy(R->hosttest,R->hostname);
  15762.  
  15763.  hostlen = strlen(R->hosttest);
  15764.  domslen = strlen(R->mydomain);
  15765.  if (hostlen > domslen) {
  15766.    hp = R->hosttest + hostlen - domslen;
  15767.    if (!memcmp(hp, R->mydomain, domslen)) *hp = '\0';
  15768.  }
  15769.  
  15770.  printf("%s Connection from %s (%s, aka %s).  Socket %d\n",
  15771.         timestamp,
  15772.         inet_ntoa(clientaddress.sin_addr), R->hostname, R->hosttest,
  15773.         R->sockfd);
  15774.  
  15775.  R->buffer[0] = '\0';
  15776.  bufptr = R->buffer;
  15777.  
  15778. /***********************/
  15779. /*  NOTE:  sometimes, if timing is right, RECV can return a 0 length */
  15780. /* record when a connection is closed by the client!!  below is a   */
  15781. /* hack to check for a 0 length record, and then terminate this     */
  15782. /* connection if we got one.                                        */
  15783. /***********************/
  15784.  
  15785. #define RECV_SIZE       (sizeof(R->buffer)-1)
  15786.  
  15787.  for (;;) {
  15788.    if (is_debug) {
  15789.      fprintf(stdout,"recv (sock=%d,size=%d)...\n",R->sockfd,RECV_SIZE);
  15790.      fflush(stdout);
  15791.    }
  15792.    if ((len=recv(R->sockfd,outbuf,RECV_SIZE,0)) <= 0) {
  15793.      REPORT_TCP_ERROR("RECV - ");
  15794.      printf("%s tcp error! len=%d\n",R->hostname, len);
  15795.      break;
  15796.    }
  15797.    *(outbuf+(len))=0;    /*make sure it's null terminated...*/
  15798.    ASCII_TO_EBCDIC(outbuf,len);
  15799.    if (is_debug) {
  15800.      int i;
  15801.      fprintf(stdout,"recv length = %d\n",len);
  15802.      for (i=0;i<len;i++) {
  15803.        if (isprint(outbuf[i])) fprintf(stdout,"%c",outbuf[i]);
  15804.        else                    fprintf(stdout,"<0x%2.2x>",outbuf[i]);
  15805.      }
  15806.      fprintf(stdout,"\n");
  15807.      fflush(stdout);
  15808.    }
  15809.    if (strlen(R->buffer) + strlen(outbuf) >= sizeof(R->buffer)) {
  15810.      fprintf(stderr, "\nError: More than %d bytes seen without CRLF\n",
  15811.              RECV_SIZE);
  15812.      len = 0;
  15813.      break;
  15814.    }
  15815.    strcat(R->buffer,outbuf);
  15816.    bufptr=R->buffer+(strlen(R->buffer)-2);
  15817.    if (*bufptr == CARRIAGE_RETURN && *(bufptr+1) == LINE_FEED) break;
  15818.    /* hack for broken Mac Mosaic client */
  15819.    if (*bufptr == LINE_FEED && *(bufptr+1) == CARRIAGE_RETURN) break;
  15820.  }
  15821.  
  15822.  if (len < 0) {
  15823.    fprintf(stderr,"%s %s Error reading %s\n",timestamp,R->hostname);
  15824.  }
  15825.  else if (len == 0) {
  15826.    fprintf(stderr,"%s %s Null input from %s\n",timestamp,R->hostname);
  15827.  }
  15828.  else {
  15829.    strcpy(echobuf,R->buffer);
  15830.    buflen = strlen(echobuf);
  15831.    if (buflen == 0) *echobuf = '\n';
  15832.    else if (buflen == 1) {
  15833.      cp = echobuf;
  15834.      if (*cp == CARRIAGE_RETURN || *cp == LINE_FEED) *cp = '\n';
  15835.    }
  15836.    else {
  15837.      cp = echobuf + buflen - 2;
  15838.      if (*cp == CARRIAGE_RETURN && *(cp+1) == LINE_FEED) {
  15839.        *cp = '\n';
  15840.        *(cp+1) = '\0';
  15841.      }
  15842.      else {
  15843.        cp++;
  15844.        if (*cp == CARRIAGE_RETURN || *cp == LINE_FEED) *cp = '\n';
  15845.      }
  15846.    }
  15847.    fprintf(stderr,"%s %s Client data:%s",
  15848.                   timestamp,R->hostname,echobuf);
  15849.    (void)GGproc(R,FALSE);
  15850.  }
  15851.  
  15852.  fflush(stdout);
  15853.  fflush(stderr);
  15854.  
  15855. #ifdef DEBUGMTF
  15856.  lookatsocket(R->sockfd);
  15857. #endif
  15858.  
  15859.  if (is_debug) {
  15860.    fprintf(stdout,"close (%d)...\n",R->sockfd);
  15861.    fflush(stdout);
  15862.  }
  15863.  
  15864.  if(close(R->sockfd)<0) REPORT_TCP_ERROR("CLOSE - ");
  15865.  
  15866. }
  15867. ./ ADD NAME=GGTEMP
  15868.  
  15869.  /********************************************************************/
  15870.  /*                                                                  */
  15871.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  15872.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  15873.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  15874.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  15875.  /*                                                                  */
  15876.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  15877.  /* including the implied warranties of merchantability and fitness, */
  15878.  /* are expressly denied.                                            */
  15879.  /*                                                                  */
  15880.  /* Provided this copyright notice is included, this software may    */
  15881.  /* be freely distributed and not offered for sale.                  */
  15882.  /*                                                                  */
  15883.  /* Changes or modifications may be made and used only by the maker  */
  15884.  /* of same, and not further distributed.  Such modifications should */
  15885.  /* be mailed to the author for consideration for addition to the    */
  15886.  /* software and incorporation in subsequent releases.               */
  15887.  /*                                                                  */
  15888.  /********************************************************************/
  15889.  
  15890. #pragma  csect(code,  "GG@TEMP")
  15891. #pragma  csect(static,"GG$TEMP")
  15892.  
  15893. #include "gg.h"
  15894.  
  15895. /*===================================================================*/
  15896.  
  15897. FILE *
  15898. GGtemp(RECV     *R,
  15899.        TEMPFILE *tp,
  15900.        TMPFUN    tempfunction
  15901.       )
  15902. {
  15903.  FILE            *rfp = NULL;
  15904.  
  15905.  switch (tempfunction) {
  15906.    case TEMP_CREATE:
  15907.         strcpy(tp->ddname,"dd:");
  15908.         if (!tmpnam(tp->dsname)) {
  15909.           fprintf(stderr, "GGtemp: Can't create temporary file\n");
  15910.         }
  15911.         if (GGalloc(tp->dsname,tp->ddname+3,SEQ,500) != SEQ) {
  15912.           fprintf(stderr, "GGtemp: Can't allocate temporary file\n");
  15913.         }
  15914.         if (tp->crmode == RBIN) rfp = OPEN_FTP_BINARY_FILE(tp->ddname);
  15915.         else                    rfp = OPEN_FTP_TEMP_FILE(tp->ddname);
  15916.         if (!rfp) {
  15917.           perror(tp->dsname);
  15918.           fprintf(stderr, "GOPHER: Can't open temporary file\n");
  15919.         }
  15920.         tp->fp = rfp;
  15921.         break;
  15922.    case TEMP_CLOSE:
  15923.         if (fclose(tp->fp) < 0) {
  15924.           fprintf(stderr, "GGtemp: Can't close temporary file\n");
  15925.         }
  15926.         else rfp = tp->fp;
  15927.         break;
  15928.    case TEMP_REMOVE:
  15929.         GGunalc(tp->ddname+3);
  15930.         if (remove(tp->dsname) < 0) {
  15931.           fprintf(stderr, "GGtemp: Can't remove temporary file\n");
  15932.         }
  15933.         else rfp = tp->fp;
  15934.         break;
  15935.  
  15936.  }
  15937.  if (!rfp) {
  15938.    GGbarf(R, "Sorry, the GOPHER server couldn't service the request");
  15939.  }
  15940.  return rfp;
  15941.  
  15942. }
  15943.  
  15944. ./ ADD NAME=GGTNET
  15945.  
  15946.  /********************************************************************/
  15947.  /*                                                                  */
  15948.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  15949.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  15950.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  15951.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  15952.  /*                                                                  */
  15953.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  15954.  /* including the implied warranties of merchantability and fitness, */
  15955.  /* are expressly denied.                                            */
  15956.  /*                                                                  */
  15957.  /* Provided this copyright notice is included, this software may    */
  15958.  /* be freely distributed and not offered for sale.                  */
  15959.  /*                                                                  */
  15960.  /* Changes or modifications may be made and used only by the maker  */
  15961.  /* of same, and not further distributed.  Such modifications should */
  15962.  /* be mailed to the author for consideration for addition to the    */
  15963.  /* software and incorporation in subsequent releases.               */
  15964.  /*                                                                  */
  15965.  /********************************************************************/
  15966.  
  15967. #pragma  csect(code,  "GG@TNET ")
  15968. #pragma  csect(static,"GG$TNET ")
  15969. #include "gg.h"
  15970.  
  15971. /* Additional code by Denis De La Roca <denis@mvs.oac.ucla.edu> */
  15972.  
  15973. /****** Gopher TELNET interface. *************************************/
  15974.  
  15975. Bool
  15976. GGtnet(gp,ip,how)
  15977. RGGCB *gp;
  15978. RINFO *ip;
  15979. GOHOW  how;
  15980. {
  15981.  int   tsorc;
  15982.  int   cnt          = 0;
  15983.  char *userid       = NULL;
  15984.  char *password     = NULL;
  15985.  char  tpath  [128];
  15986.  char  tsocmd [256];
  15987.  char  tstuff [256];
  15988.  
  15989.  switch (how) {
  15990.    case AS_NORMAL: break;
  15991.    default:
  15992.             ERR1("TELNET interface cannot be viewed as a file.");
  15993.             return FALSE;
  15994.  }
  15995.  
  15996.  ISPF("CONTROL DISPLAY LINE");
  15997.  
  15998.  /* Parse userid/password for Xtelnet's autologin */
  15999.  
  16000. #ifdef XTELNET_AUTOLOGIN
  16001.  
  16002.  if (EQUAL(gp->mytelnet, "XTELNET") && *ip->path) {
  16003.  
  16004.    strcpy(tpath, ip->path);
  16005.    userid = tpath;
  16006.    password = strchr(tpath, ',');
  16007.    if (password) {
  16008.      *password = '\0';
  16009.      password = strchr(password + 1, ':');
  16010.      if (password) {
  16011.        if (!memcmp(password - 7, "assword", 7)) password += 2;
  16012.        else                                     password = NULL;
  16013.      }
  16014.    }
  16015.    cnt += sprintf(tsocmd+cnt, "%s -l %s", gp->mytelnet, userid);
  16016.    if (password)
  16017.       cnt += sprintf(tsocmd+cnt, "/%s", password);
  16018.    cnt += sprintf(tsocmd+cnt, " %s", ip->host);
  16019.    if (ip->port > 0)
  16020.       cnt += sprintf(tsocmd+cnt, " %d", ip->port);
  16021.  }
  16022.  
  16023.  else { /* IBM's Telnet does not support autologin */
  16024.  
  16025. #endif
  16026.  
  16027.    /* Print note only if we have non-null path */
  16028.  
  16029.    if (*ip->path) {
  16030.      fprintf(stderr,"Note: Login as user: %s\n\n", ip->path);
  16031.    }
  16032.  
  16033.    if (ip->port==0) sprintf(tsocmd,"%s %s",gp->mytelnet,ip->host);
  16034.    else sprintf(tsocmd,"%s %s %d",gp->mytelnet,ip->host,ip->port);
  16035.  
  16036. #ifdef XTELNET_AUTOLOGIN
  16037.  
  16038.  }
  16039.  
  16040. #endif
  16041.  
  16042.  if ((tsorc = GGtso(tsocmd)) != 0) {
  16043.    ERR3("Command \"%s\" returned code %d", tsocmd, tsorc);
  16044.  }
  16045.  
  16046.  ISPF("CONTROL DISPLAY REFRESH");
  16047.  
  16048.  return TRUE;
  16049. }
  16050.  
  16051. ./ ADD NAME=GGTSO
  16052.  
  16053.  /********************************************************************/
  16054.  /*                                                                  */
  16055.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  16056.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  16057.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  16058.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  16059.  /*                                                                  */
  16060.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  16061.  /* including the implied warranties of merchantability and fitness, */
  16062.  /* are expressly denied.                                            */
  16063.  /*                                                                  */
  16064.  /* Provided this copyright notice is included, this software may    */
  16065.  /* be freely distributed and not offered for sale.                  */
  16066.  /*                                                                  */
  16067.  /* Changes or modifications may be made and used only by the maker  */
  16068.  /* of same, and not further distributed.  Such modifications should */
  16069.  /* be mailed to the author for consideration for addition to the    */
  16070.  /* software and incorporation in subsequent releases.               */
  16071.  /*                                                                  */
  16072.  /********************************************************************/
  16073.  
  16074.  /********************************************************************/
  16075.  /*                                                                  */
  16076.  /* Thanks to Michael Van Norman for this code.                      */
  16077.  /*                                                                  */
  16078.  /********************************************************************/
  16079.  
  16080. #pragma  csect(code,  "GG@TSO  ")
  16081. #pragma  csect(static,"GG$TSO  ")
  16082. #include "gg.h"
  16083.  
  16084. #pragma linkage(ikjeftsr,OS)
  16085.  
  16086. #define _IKJEFTSR_FLAGS_AUTH        0x00000000
  16087. #define _IKJEFTSR_FLAGS_COMMAND     0x00000001
  16088. #define _IKJEFTSR_FLAGS_DUMP        0x00000100
  16089. #define _IKJEFTSR_FLAGS_NODUMP      0x00000000
  16090. #define _IKJEFTSR_FLAGS_PROGRAM     0x00000002
  16091. #define _IKJEFTSR_FLAGS_UNAUTH      0x00010000
  16092.  
  16093. /****** Issue TSO command. *******************************************/
  16094.  
  16095. int
  16096. GGtso(command)
  16097. char        *command;
  16098. {
  16099.  int         flags         = _IKJEFTSR_FLAGS_COMMAND +
  16100.                              _IKJEFTSR_FLAGS_UNAUTH;
  16101.  int         commandLength = strlen(command);
  16102.  int         rc            = 0;
  16103.  int         returnCode    = 0;
  16104.  int         reasonCode    = 0;
  16105.  int         abendCode     = 0;
  16106.  
  16107.  static int (*ikjeftsr)() = NULL;
  16108.  
  16109.  if (!ikjeftsr) {
  16110.    int tsoEntryAddress;
  16111.  
  16112.    tsoEntryAddress = 0x00000010;    /* Address of CVT */
  16113.    tsoEntryAddress = *(int *)(tsoEntryAddress);
  16114.    tsoEntryAddress += 0x9C;/*       /* Offset of TVT in CVT */
  16115.    tsoEntryAddress = *(int *)(tsoEntryAddress);
  16116.    tsoEntryAddress += 0x10;/*       /* TSVTASF-TSVT (from IKJTSVT) */
  16117.    tsoEntryAddress = *(int *)(tsoEntryAddress);
  16118. #ifndef SASC
  16119.    ikjeftsr = (int (*)())(tsoEntryAddress);
  16120. #else
  16121.    ikjeftsr = (__ibmos int (*)())(tsoEntryAddress);
  16122. #endif
  16123.  }
  16124.  
  16125.  if (!ikjeftsr) {
  16126.    fprintf(stderr,
  16127.            "Cannot execute TSO commands, can't fetch IKJEFTSR.\n");
  16128.    return -2;
  16129.  }
  16130.  
  16131.  rc = (*ikjeftsr)(&flags, command, &commandLength,
  16132.                           &returnCode, &reasonCode,
  16133.                           (int *)((int)(&abendCode) | 0x80000000));
  16134.  
  16135.  if (rc != 0) {
  16136.    if (rc > 4) {
  16137.      fprintf(stderr,"Command failed:%s\n",command);
  16138.      if (rc == 20 && reasonCode == 40)
  16139.           fprintf(stderr,"Command was not found.\n");
  16140.      else fprintf(stderr,
  16141.              "rc=%d,returncode=%d,reasoncode=%d,abendcode=%8.8x\n",
  16142.              rc, returnCode, reasonCode, abendCode);
  16143.    }
  16144.    if (abendCode != 0) rc = -1;
  16145.    else rc = returnCode;
  16146.  }
  16147.  
  16148.  return rc;
  16149. }
  16150.  
  16151. ./ ADD NAME=GGTYPE
  16152.  
  16153.  /********************************************************************/
  16154.  /*                                                                  */
  16155.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  16156.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  16157.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  16158.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  16159.  /*                                                                  */
  16160.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  16161.  /* including the implied warranties of merchantability and fitness, */
  16162.  /* are expressly denied.                                            */
  16163.  /*                                                                  */
  16164.  /* Provided this copyright notice is included, this software may    */
  16165.  /* be freely distributed and not offered for sale.                  */
  16166.  /*                                                                  */
  16167.  /* Changes or modifications may be made and used only by the maker  */
  16168.  /* of same, and not further distributed.  Such modifications should */
  16169.  /* be mailed to the author for consideration for addition to the    */
  16170.  /* software and incorporation in subsequent releases.               */
  16171.  /*                                                                  */
  16172.  /********************************************************************/
  16173.  
  16174. #pragma  csect(code,  "GG@TYPE ")
  16175. #pragma  csect(static,"GG$TYPE ")
  16176. #include "gg.h"
  16177.  
  16178. /*********************************************************************/
  16179.  
  16180. char *
  16181. GGtype(GOPHERTYPE t)
  16182. {
  16183.  
  16184.  switch (t) {
  16185.    case GOPHER_FILE:        return "File     ";
  16186.    case GOPHER_DIRECTORY:   return "Directory";
  16187.    case GOPHER_CSO:         return "Cso      ";
  16188.    case GOPHER_ERROR:       return "Error    ";
  16189.    case GOPHER_MAC_BINHEX:  return "Binhex   ";
  16190.    case GOPHER_DOS_BINARCH: return "Binarch  ";
  16191.    case GOPHER_UUENCODE:    return "Uuencode ";
  16192.    case GOPHER_WAIS:        return "Index    ";
  16193.    case GOPHER_TELNET:      return "Telnet   ";
  16194.    case GOPHER_TN3270:      return "TN3270   ";
  16195.    case GOPHER_BINARY:      return "Binary   ";
  16196.    case GOPHER_IMAGE:       return "Image    ";
  16197.    case GOPHER_BOOKMANAGER: return "BookMgr  ";
  16198.    case GOPHER_COMMENT:     return "         ";
  16199.    case GOPHER_REDUNDANT:   return "Redundant";
  16200.    case GOPHER_WHOIS:       return "Whois    ";
  16201.    default:                 return "Unknown  ";
  16202.  }
  16203. }
  16204.  
  16205. ./ ADD NAME=GGUNALC
  16206.  
  16207.  /********************************************************************/
  16208.  /*                                                                  */
  16209.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  16210.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  16211.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  16212.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  16213.  /*                                                                  */
  16214.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  16215.  /* including the implied warranties of merchantability and fitness, */
  16216.  /* are expressly denied.                                            */
  16217.  /*                                                                  */
  16218.  /* Provided this copyright notice is included, this software may    */
  16219.  /* be freely distributed and not offered for sale.                  */
  16220.  /*                                                                  */
  16221.  /* Changes or modifications may be made and used only by the maker  */
  16222.  /* of same, and not further distributed.  Such modifications should */
  16223.  /* be mailed to the author for consideration for addition to the    */
  16224.  /* software and incorporation in subsequent releases.               */
  16225.  /*                                                                  */
  16226.  /********************************************************************/
  16227.  
  16228. #pragma  csect(code,  "GG@UNALC")
  16229. #pragma  csect(static,"GG$UNALC")
  16230. #include "gg.h"
  16231. #include "ggsvc99.h"
  16232.  
  16233. /****** Unallocate a data set. ***************************************/
  16234.  
  16235. Bool
  16236. GGunalc(ddname)
  16237. char   *ddname;
  16238. {
  16239.  __S99parms   stuff99;   /* The manual has it wrong.  No "struct". */
  16240.  int          rc;
  16241.  TEXTUNIT    *tu [2];
  16242.  TEXTUNIT     tu_ddn;
  16243.  TEXTUNIT     tu_una;
  16244.  
  16245.  if (!ddname || !*ddname) return TRUE;   /* if no ddname to free */
  16246.  
  16247.  CLEAR(&stuff99);
  16248.  
  16249.  stuff99.__S99RBLN   = 20;
  16250.  stuff99.__S99VERB   = S99VRBUN;
  16251.  stuff99.__S99FLAG1  = 0;
  16252.  stuff99.__S99ERROR  = 0;
  16253.  stuff99.__S99INFO   = 0;
  16254.  stuff99.__S99TXTPP  = tu;
  16255.  stuff99.__S99FLAG2  = 0;
  16256.  
  16257.  tu[0] = &tu_ddn;
  16258.  tu[1] = &tu_una;
  16259.  *(int *)&tu[1] |= 0x80000000;
  16260.  
  16261.  tu_ddn.key     = DUNDDNAM;
  16262.  tu_ddn.num     = 1;
  16263.  tu_ddn.ent.len = strlen(ddname);
  16264.  copy_uppercase(tu_ddn.ent.prm,ddname);
  16265.  
  16266.  tu_una.key     = DUNUNALC;
  16267.  tu_una.num     = 0;
  16268.  
  16269.  rc = svc99(&stuff99);
  16270.  
  16271.  if (rc == 0) return TRUE;
  16272.  else if (stuff99.__S99ERROR == 0x0438) /* not freed, is not allocated*/
  16273.          return TRUE;
  16274.  else {
  16275.    GGdfail(rc,&stuff99);
  16276.    return FALSE;
  16277.  }
  16278. }
  16279.  
  16280. ./ ADD NAME=GGVIEW
  16281.  
  16282.  /********************************************************************/
  16283.  /*                                                                  */
  16284.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  16285.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  16286.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  16287.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  16288.  /*                                                                  */
  16289.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  16290.  /* including the implied warranties of merchantability and fitness, */
  16291.  /* are expressly denied.                                            */
  16292.  /*                                                                  */
  16293.  /* Provided this copyright notice is included, this software may    */
  16294.  /* be freely distributed and not offered for sale.                  */
  16295.  /*                                                                  */
  16296.  /* Changes or modifications may be made and used only by the maker  */
  16297.  /* of same, and not further distributed.  Such modifications should */
  16298.  /* be mailed to the author for consideration for addition to the    */
  16299.  /* software and incorporation in subsequent releases.               */
  16300.  /*                                                                  */
  16301.  /********************************************************************/
  16302.  
  16303. #pragma  csect(code,  "GG@VIEW ")
  16304. #pragma  csect(static,"GG$VIEW ")
  16305. #include "gg.h"
  16306.  
  16307. struct cmddesc {
  16308.                 char    command_name[COMMANDSIZE];
  16309.                 Bool    (*command_processor)();
  16310.                };
  16311.  
  16312. struct browser {
  16313.           GOPHERINFO    *ip;
  16314.           TEXTHDR       *thp;            /* text header pointer      */
  16315.           TEXTLINE     **tv;             /* text vector              */
  16316.                char     *bda;            /* dynamic area address     */
  16317.                char     *work;           /* find work area address   */
  16318.                char     *firstpos;       /* beginning of actual data */
  16319.                char     *lastpos;        /* end of actual data       */
  16320.                int       depth;          /* dynamic area depth       */
  16321.                int       lvl;            /* last visible line        */
  16322.                int       size;           /* dynamic area size        */
  16323.                int       more_rows;      /* Scroll request row count */
  16324.                int       rowfactor;      /* # physical rows per line */
  16325.                int       screenbump;     /* # physical rows * width  */
  16326.                int       top;            /* top row number           */
  16327.                int       total;          /* total number of rows     */
  16328.                int       coloff;         /* offset from LEFT/RIGHT   */
  16329.                int       cols;           /* 1 if COLS done, else 0   */
  16330.                int       maxlen;         /* maximum text length      */
  16331.                int       maxcoloff;      /* maximum right scroll     */
  16332.                int       find_count;     /* used by FIND ALL         */
  16333.                int       find_row;       /* row where last found     */
  16334.                int       find_col;       /* col where last found     */
  16335.                int       found_row;      /* row where last found     */
  16336.                int       found_col;      /* col where last found     */
  16337.                int       csrpos;         /* cursor position          */
  16338.                int       find_csrpos;    /* col where last found     */
  16339.                int       found_left;     /* pos left of found string */
  16340.                int       found_right;    /* pos right of found string*/
  16341.                Bool      override_scroll;/* set by some commands     */
  16342.                Bool      highlighted;    /* set if FIND highlights   */
  16343.                Bool      reinit_browse;  /* set if text changed      */
  16344.                Bool      exit_browse;    /* set if browse must exit  */
  16345.                Bool      find_hit_end;   /* top/bottom of data reach */
  16346.                char      cursor     [9]; /* cursor field name        */
  16347.                char      find_cursor[9]; /* row where last found     */
  16348.                char      title     [81]; /* title                    */
  16349.                char      cols_line [81]; /* cols line                */
  16350.                char      zcmd      [81]; /* command input            */
  16351.               };
  16352.  
  16353. /******* EXTRACT command **********************************************/
  16354.  
  16355. static Bool
  16356. process_extract_command(gp,bp,operands)
  16357. RGGCB               *gp;
  16358. struct browser      *bp;
  16359. char                *operands;
  16360. {
  16361.  RINFO              *ip = bp->ip;
  16362.  
  16363.  gp->extract_file = NULL;
  16364.  
  16365.  ISPF("CONTROL DISPLAY SAVE");
  16366.  (void)GGxtx(gp,ip,EXTRACT_IT);                   /* Extract text */
  16367.  ISPF("CONTROL DISPLAY RESTORE");
  16368.  
  16369.  return TRUE;
  16370. }
  16371.  
  16372. /******* PRINT command ************************************************/
  16373.  
  16374. static Bool
  16375. process_print_command(gp,bp,operands)
  16376. RGGCB               *gp;
  16377. struct browser      *bp;
  16378. char                *operands;
  16379. {
  16380.  RINFO              *ip = bp->ip;
  16381.  
  16382.  gp->extract_file = NULL;
  16383.  
  16384.  ISPF("CONTROL DISPLAY SAVE");
  16385.  (void)GGxtx(gp,ip,PRINT_IT);                   /* Print text */
  16386.  ISPF("CONTROL DISPLAY RESTORE");
  16387.  
  16388.  return TRUE;
  16389. }
  16390.  
  16391. /******* INFO command. ************************************************/
  16392.  
  16393. static Bool
  16394. process_info_command(gp,bp,operands)
  16395. RGGCB               *gp;
  16396. struct browser      *bp;
  16397. char                *operands;
  16398. {
  16399.  RINFO              *ip = bp->ip;
  16400.  
  16401.  if (!GGinfo(gp,ip)) return FALSE;
  16402.  
  16403.  ISPF("CONTROL DISPLAY SAVE");
  16404.  (void)GGvtx(gp,NULL,TRUE);              /* View text */
  16405.  ISPF("CONTROL DISPLAY RESTORE");
  16406.  
  16407.  return TRUE;
  16408. }
  16409.  
  16410. /******* BOOKMARK command. ********************************************/
  16411.  
  16412. static Bool
  16413. process_bookmark_command(gp,bp,operands)
  16414. RGGCB               *gp;
  16415. struct browser      *bp;
  16416. char                *operands;
  16417. {
  16418.  RINFO              *ip = bp->ip;
  16419.  
  16420.  if (!GGinfo(gp,ip)) return FALSE;
  16421.  
  16422.  gp->extract_file = NULL;
  16423.  
  16424.  ISPF("CONTROL DISPLAY SAVE");
  16425.  (void)GGxtx(gp,ip,BOOKMARK_IT);       /* save as bookmark */
  16426.  ISPF("CONTROL DISPLAY RESTORE");
  16427.  
  16428.  return TRUE;
  16429. }
  16430.  
  16431. /******* OPTIONS command **********************************************/
  16432.  
  16433. static Bool
  16434. process_options_command(gp,bp,operands)
  16435. RGGCB               *gp;
  16436. struct browser      *bp;
  16437. char                *operands;
  16438. {
  16439.  
  16440.  GGdsopt(gp,operands);
  16441.  
  16442.  return TRUE;
  16443. }
  16444.  
  16445. /******* QUIT command *************************************************/
  16446.  
  16447. static Bool
  16448. process_quit_command(gp,bp,operands)
  16449. RGGCB               *gp;
  16450. struct browser      *bp;
  16451. char                *operands;
  16452. {
  16453.  
  16454.  gp->quit = TRUE;
  16455.  
  16456.  return TRUE;
  16457. }
  16458.  
  16459. /******* COLS command *************************************************/
  16460.  
  16461. static Bool
  16462. process_cols_command(gp,bp,operands)
  16463. RGGCB               *gp;
  16464. Rstruc browser      *bp;
  16465. char                *operands;
  16466. {
  16467.  
  16468.  bp->cols = 1;
  16469.  *bp->cols_line = '\0';
  16470.  bp->reinit_browse = TRUE;
  16471.  return TRUE;
  16472. }
  16473.  
  16474. /******* RESET command ************************************************/
  16475.  
  16476. static Bool
  16477. process_reset_command(gp,bp,operands)
  16478. RGGCB               *gp;
  16479. Rstruc browser      *bp;
  16480. char                *operands;
  16481. {
  16482.  
  16483.  bp->cols = 0;
  16484.  *bp->cols_line = '\0';
  16485.  bp->reinit_browse = TRUE;
  16486.  return TRUE;
  16487. }
  16488.  
  16489. /******* DISPLAY command **********************************************/
  16490.  
  16491. static Bool
  16492. process_display_command(gp,bp,operands)
  16493. RGGCB               *gp;
  16494. Rstruc browser      *bp;
  16495. char                *operands;
  16496. {
  16497.  unsigned int        u;
  16498.  
  16499.  switch (strlen(operands)) {
  16500.    case 1: gp->text_dispchar = operands[0];
  16501.            break;
  16502.    case 2: if (1 != sscanf(operands,"%x",&u)) {
  16503.              ERR1("Invalid hex character representation.");
  16504.              return FALSE;
  16505.            }
  16506.            gp->text_dispchar = u;
  16507.            break;
  16508.    default:
  16509.            ERR1("A single character must be specified.");
  16510.            return FALSE;
  16511.  }
  16512.  bp->reinit_browse = TRUE;
  16513.  return TRUE;
  16514. }
  16515.  
  16516. /******* LOCATE command ***********************************************/
  16517.  
  16518. static Bool
  16519. process_locate_command(gp,bp,operands)
  16520. RGGCB               *gp;
  16521. Rstruc browser      *bp;
  16522. char                *operands;
  16523. {
  16524.  int                 locnum;
  16525.  char                junk[72];
  16526.  
  16527.  if (1 != sscanf(operands, "%d %s", &locnum, junk)) {
  16528.    ERR1("The LOCATE command requires a line number.");
  16529.    return FALSE;
  16530.  }
  16531.  
  16532.  bp->top = locnum;
  16533.  bp->more_rows = 0;
  16534.  bp->override_scroll = TRUE;
  16535.  bp->reinit_browse = TRUE;
  16536.  return TRUE;
  16537. }
  16538.  
  16539. /***** Helper functions for FIND **************************************/
  16540.  
  16541. /*--------------------------------------------------------------------*
  16542.  * Get quoted FIND string.                                            *
  16543.  *--------------------------------------------------------------------*/
  16544.  
  16545. static char *
  16546. get_quoted_find_string(gp,cp,qform)
  16547. RGGCB               *gp;
  16548. register char       *cp;
  16549. char                *qform;
  16550. {
  16551.  char                quote     = *cp;
  16552.  char                termchar  = '\0';
  16553.  
  16554.  for (cp++;;cp++) {
  16555.    if (*cp == quote) {
  16556.      switch (*(cp+1)) {
  16557.        case '\0':
  16558.        case ' ':  termchar = '\0'; break;
  16559.        case 'c':
  16560.        case 'C':  termchar = 'C' ; break;
  16561.        case 't':
  16562.        case 'T':  termchar = 'T' ; break;
  16563.        case 'x':
  16564.        case 'X':  termchar = 'X' ; break;
  16565.        case 'p':
  16566.        case 'P':  termchar = 'P' ; break;
  16567.        default:   continue;
  16568.      }
  16569.      if (termchar) {
  16570.        switch (*(cp+2)) {
  16571.          case '\0':
  16572.          case ' ':  break;
  16573.          default:   continue;
  16574.        }
  16575.        if (*qform != FIND_QUOTED) {
  16576.          ERR1(
  16577.       "Invalid string; Do not surround a quoted string with letters.");
  16578.          *qform = FIND_BADFORM;
  16579.          return NULL;
  16580.        }
  16581.        else {
  16582.          switch (termchar) {
  16583.            case 'C': *qform = FIND_C; break;
  16584.            case 'T': *qform = FIND_T; break;
  16585.            case 'X': *qform = FIND_X; break;
  16586.            case 'P': *qform = FIND_P; break;
  16587.          }
  16588.          *cp = '\0'; /* kill the quote because it's the character */
  16589.          cp++;       /* that the caller will kill, not the quote */
  16590.        }
  16591.      }
  16592.      break;
  16593.    }
  16594.    else if (!*cp) {
  16595.      ERR1(
  16596.      "Missing quote; The FIND command requires balanced quote marks.");
  16597.      *qform = FIND_BADFORM;
  16598.      return NULL;
  16599.    }
  16600.  }
  16601.  return cp;
  16602. }
  16603.  
  16604. /*--------------------------------------------------------------------*
  16605.  * Get FIND operand.                                                  *
  16606.  *--------------------------------------------------------------------*/
  16607.  
  16608. static char *
  16609. get_find_operand(gp,opp,qform)
  16610. RGGCB           *gp;
  16611. char           **opp;
  16612. char            *qform;
  16613. {
  16614.  register char  *cp    = skip_ISPF_whitespace(*opp);
  16615.  char           *start = NULL;
  16616.  
  16617.  if (!*cp) return NULL;
  16618.  if (*cp == '\'' || *cp == '"') {
  16619.    start = cp+1;
  16620.    *qform = FIND_QUOTED;
  16621.    if (!(cp = get_quoted_find_string(gp,cp,qform))) return NULL;
  16622.  }
  16623.  else if ((*(cp+1) == '\'' || *(cp+1) == '"')) {
  16624.    switch (*cp) {
  16625.      case 'c':
  16626.      case 'C': *qform = FIND_C; break;
  16627.      case 't':
  16628.      case 'T': *qform = FIND_T; break;
  16629.      case 'x':
  16630.      case 'X': *qform = FIND_X; break;
  16631.      case 'p':
  16632.      case 'P': *qform = FIND_P; break;
  16633.      default:  *qform = FIND_UNQUOTED; break;
  16634.    }
  16635.    if (*qform != FIND_UNQUOTED) {
  16636.      cp++;
  16637.      start = cp+1;
  16638.      if (!(cp = get_quoted_find_string(gp,cp,qform))) return NULL;
  16639.    }
  16640.    else {
  16641.      start = cp;
  16642.      find_ISPF_whitespace(cp,start);
  16643.    }
  16644.  }
  16645.  else {
  16646.    start = cp;
  16647.    *qform = FIND_UNQUOTED;
  16648.    find_ISPF_whitespace(cp,start);
  16649.  }
  16650.  if (*cp) {
  16651.    *cp  = '\0';
  16652.    *opp = cp+1;
  16653.  }
  16654.  else *opp = cp;
  16655.  return start;
  16656. }
  16657.  
  16658. /*--------------------------------------------------------------------*
  16659.  * Find it.                                                           *
  16660.  *--------------------------------------------------------------------*/
  16661.  
  16662. #define REND                 (r+(*tpp)->tab_expanded_text_length)
  16663. #define PRECEDED_BY_VERBIAGE (q>r && isalnum(*(q-1)))
  16664. #define FOLLOWED_BY_VERBIAGE (q+findlen<REND && isalnum(*(q+findlen)))
  16665.  
  16666. static Bool
  16667. find_it(gp,bp,find_string,findlen,
  16668.                           find_type,find_what,find_trans,
  16669.                           find_left_bound,find_right_bound)
  16670. RGGCB             *gp;
  16671. Rstruc browser    *bp;
  16672. char              *find_string;
  16673. int                findlen;
  16674. char               find_type;      /* chars word prefix suffix */
  16675. char               find_what;      /* next prev first last all */
  16676. char               find_trans;     /* caps asis generic        */
  16677. int                find_left_bound;
  16678. int                find_right_bound;
  16679. {
  16680.  TEXTLINE        **tpp;
  16681.  char             *p;
  16682.  char             *q;
  16683.  char             *r;
  16684.  int               row  = bp->find_row;
  16685.  int               col  = bp->find_col;
  16686.  int               lcol = find_left_bound - 1;
  16687.  int               rcol = find_right_bound - 1;
  16688.  int               ecol;
  16689.  int               complen;
  16690.  Bool              backward_find;
  16691.  
  16692.  switch (find_what) {
  16693.    case FIND_NEXT:
  16694.                     if (bp->find_hit_end) {
  16695.                       bp->find_hit_end = FALSE;
  16696.                       row = 0;
  16697.                       col = lcol;
  16698.                     }
  16699.                     else if (EQUAL(bp->find_cursor,"GGBDYNA")) {
  16700.                       row = bp->top+((bp->find_csrpos-1)/80)-bp->cols-1;
  16701.                       col = (bp->find_csrpos-1) % 80 + bp->coloff;
  16702.                       if (++col >= bp->maxlen) {
  16703.                         row++;
  16704.                         col = lcol;
  16705.                       }
  16706.                     }
  16707.                     else {
  16708.                       row = bp->top - 1;
  16709.                       if (row < 0) row = 0;
  16710.                       col = lcol;
  16711.                     }
  16712.                     backward_find = FALSE;
  16713.                     break;
  16714.    case FIND_PREV:
  16715.                     if (bp->find_hit_end) {
  16716.                       bp->find_hit_end = FALSE;
  16717.                       row = bp->total - 1;
  16718.                       col = rcol;
  16719.                     }
  16720.                     else if (EQUAL(bp->find_cursor,"GGBDYNA")) {
  16721.                       row = bp->top+((bp->find_csrpos-1)/80)-bp->cols-1;
  16722.                       col = (bp->find_csrpos-1) % 80 + bp->coloff;
  16723.                       if (--col < 0) {
  16724.                         row--;
  16725.                         col = rcol;
  16726.                       }
  16727.                     }
  16728.                     else {
  16729.                       row = bp->total - 1;
  16730.                       col = rcol;
  16731.                     }
  16732.                     backward_find = TRUE;
  16733.                     break;
  16734.    case FIND_FIRST:
  16735.                     bp->find_hit_end = FALSE;
  16736.                     row = 0;
  16737.                     col = lcol;
  16738.                     backward_find = FALSE;
  16739.                     break;
  16740.    case FIND_LAST:
  16741.                     bp->find_hit_end = FALSE;
  16742.                     row = bp->total - 1;
  16743.                     col = rcol;
  16744.                     backward_find = TRUE;
  16745.                     break;
  16746.    case FIND_ALL:
  16747.                     col++;
  16748.                     backward_find = FALSE;
  16749.                     break;
  16750.  }
  16751.  
  16752.  if (!backward_find) { /* forward find */
  16753.    if (col < lcol) col = lcol;
  16754.    else if (col > rcol) {
  16755.      col = lcol;
  16756.      row++;
  16757.    }
  16758.    for (tpp = &bp->tv[row]; row < bp->total; tpp++, col=lcol, row++) {
  16759.      ecol = (*tpp)->tab_expanded_text_length - 1;
  16760.      if (ecol > rcol) ecol = rcol;
  16761.      if (col > ecol) continue;
  16762.      p = (*tpp)->tab_expanded_text;
  16763.      if (find_trans == FIND_CAPS) {
  16764.        copy_uppercase(bp->work,p);
  16765.        r = bp->work;
  16766.      }
  16767.      else r = p;
  16768.      complen = ecol-col+1;
  16769.      for (q = r + col;;q++) {
  16770.        q = memchr(q,find_string[0],complen);
  16771.        if (!q) break;
  16772.        col = q - r;
  16773.        complen = ecol-col+1;
  16774.        if (complen < findlen) break;
  16775.        if (!memcmp(q,find_string,findlen)) {
  16776.          switch (find_type) {
  16777.            case FIND_CHARS:  break;
  16778.            case FIND_WORD:
  16779.                 if (PRECEDED_BY_VERBIAGE || FOLLOWED_BY_VERBIAGE)
  16780.                     continue;
  16781.                 break;
  16782.            case FIND_PREFIX:
  16783.                 if (PRECEDED_BY_VERBIAGE || !FOLLOWED_BY_VERBIAGE)
  16784.                     continue;
  16785.                 break;
  16786.            case FIND_SUFFIX:
  16787.                 if (!PRECEDED_BY_VERBIAGE || FOLLOWED_BY_VERBIAGE)
  16788.                    continue;
  16789.                 break;
  16790.          }
  16791.          bp->find_row = row;
  16792.          bp->find_col = col;
  16793.          return TRUE;
  16794.        }
  16795.      }
  16796.    }
  16797.    bp->find_row = 0;
  16798.    bp->find_col = 0;
  16799.    bp->find_hit_end = TRUE;
  16800.    return FALSE;
  16801.  }
  16802.  else { /* backward find */
  16803.    if (row >= bp->total) row = bp->total - 1;
  16804.    if (col > rcol-findlen+1) col = rcol-findlen+1;
  16805.    else if (col < lcol) {
  16806.      col = rcol-findlen+1;
  16807.      row--;
  16808.    }
  16809.    for (tpp=&bp->tv[row]; row >= 0; tpp--, col=rcol-findlen+1, row--) {
  16810.      ecol = (*tpp)->tab_expanded_text_length - 1;
  16811.      if (ecol > rcol) ecol = rcol;
  16812.      if (col > ecol) col = ecol;
  16813.      p = (*tpp)->tab_expanded_text;
  16814.      if (find_trans == FIND_CAPS) {
  16815.        copy_uppercase(bp->work,p);
  16816.        r = bp->work;
  16817.      }
  16818.      else r = p;
  16819.      for (q = r + col; q >= r; q--) {
  16820.        if (!memcmp(q,find_string,findlen)) {
  16821.          switch (find_type) {
  16822.            case FIND_CHARS:  break;
  16823.            case FIND_WORD:
  16824.                 if (PRECEDED_BY_VERBIAGE || FOLLOWED_BY_VERBIAGE)
  16825.                     continue;
  16826.                 break;
  16827.            case FIND_PREFIX:
  16828.                 if (PRECEDED_BY_VERBIAGE || !FOLLOWED_BY_VERBIAGE)
  16829.                     continue;
  16830.                 break;
  16831.            case FIND_SUFFIX:
  16832.                 if (!PRECEDED_BY_VERBIAGE || FOLLOWED_BY_VERBIAGE)
  16833.                    continue;
  16834.                 break;
  16835.          }
  16836.          col = q - r;
  16837.          bp->find_row = row;
  16838.          bp->find_col = col;
  16839.          return TRUE;
  16840.        }
  16841.      }
  16842.    }
  16843.    bp->find_row = bp->total - 1;
  16844.    bp->find_col = bp->maxlen;
  16845.    bp->find_hit_end = TRUE;
  16846.    return FALSE;
  16847.  }
  16848. }
  16849.  
  16850. /********* FIND command ***********************************************/
  16851.  
  16852. static Bool
  16853. process_find_command(gp,bp,operands)
  16854. RGGCB               *gp;
  16855. Rstruc browser      *bp;
  16856. char                *operands;
  16857. {
  16858.  char        *find_operand [64];
  16859.  char        *show_type;
  16860.  char        *cp;
  16861.  char        *opcopy;
  16862.  char        *op;
  16863.  char        *p;
  16864.  char        *q;
  16865.  int          find_operand_count = 0;
  16866.  int          ox;
  16867.  int          find_left_bound;
  16868.  int          find_right_bound;
  16869.  int          n;
  16870.  int          len;
  16871.  int          findlen;
  16872.  Bool         finderror              = FALSE;
  16873.  Bool         out_of_bounds          = FALSE;
  16874.  Bool         hit_end                = FALSE;
  16875.  Bool         find_string_given      = FALSE;
  16876.  Bool         find_what_given        = FALSE;
  16877.  Bool         find_type_given        = FALSE;
  16878.  Bool         find_left_bound_given  = FALSE;
  16879.  Bool         find_right_bound_given = FALSE;
  16880.  char         find_what;      /* next prev first last all */
  16881.  char         find_type;      /* chars word prefix suffix */
  16882.  char         find_trans;     /* caps asis generic        */
  16883.  char         find_form;      /* unquoted quoted c x t p  */
  16884.  char         ff;             /* unquoted quoted c x t p  */
  16885.  char         find_qform   [64];
  16886.  char         operand_copy [81];
  16887.  char         find_string  [81];
  16888.  char         temp         [81];
  16889.  char         show_string [129];
  16890.  char         shortmsg    [129];
  16891.  char         longmsg     [129];
  16892.  
  16893.  strcpy(operand_copy,operands);
  16894.  
  16895.  for (ox = 0, opcopy = operand_copy; ox < 64; ox++) {
  16896.    ff = FIND_UNQUOTED;
  16897.    op = get_find_operand(gp,&opcopy,&ff);
  16898.    if (ff == FIND_BADFORM) return FALSE;
  16899.    if (!op) break;
  16900.    find_operand[ox] = op;
  16901.    find_qform[ox] = ff;
  16902.    find_operand_count++;
  16903.  }
  16904.  
  16905.  if (find_operand_count == 0) {
  16906.    if (!*gp->text_find_string) {
  16907.      ERR1("The first FIND command requires an operand.");
  16908.      return FALSE;
  16909.    }
  16910.    strcpy(find_string,gp->text_find_string);
  16911.    find_what        = gp->text_find_what;
  16912.    find_type        = gp->text_find_type;
  16913.    find_trans       = gp->text_find_trans;
  16914.    find_left_bound  = gp->text_find_left_bound;
  16915.    find_right_bound = gp->text_find_right_bound;
  16916.  }
  16917.  else {
  16918.    find_what        = FIND_NEXT;
  16919.    find_type        = FIND_CHARS;
  16920.    find_trans       = FIND_CAPS;
  16921.    find_left_bound  = 1;
  16922.    find_right_bound = bp->maxlen;
  16923.    for (ox = 0; ox < find_operand_count; ox++) {
  16924.      op = find_operand[ox];
  16925.      ff = find_qform[ox];
  16926.      if (ff != FIND_UNQUOTED) {
  16927.        if (find_string_given) finderror = TRUE;
  16928.        else {
  16929.          strcpy(find_string,op);
  16930.          find_form = ff;
  16931.          find_string_given = TRUE;
  16932.        }
  16933.      }
  16934.      else {
  16935.        copy_uppercase(temp,op);
  16936.        if (EQUAL(temp,"*")) {
  16937.          if (find_string_given) finderror = TRUE;
  16938.          else {
  16939.            strcpy(find_string,gp->text_find_string);
  16940.            find_form = ff;
  16941.            find_string_given = TRUE;
  16942.          }
  16943.        }
  16944.        else if (find_operand_count == 1) {
  16945.          strcpy(find_string,op);
  16946.          find_form = ff;
  16947.          find_string_given = TRUE;
  16948.        }
  16949.        else if (EQUAL(temp,"NEXT")) {
  16950.          if (find_what_given) finderror = TRUE;
  16951.          else {
  16952.            find_what = FIND_NEXT;
  16953.            find_what_given = TRUE;
  16954.          }
  16955.        }
  16956.        else if (EQUAL(temp,"PREV")) {
  16957.          if (find_what_given) finderror = TRUE;
  16958.          else {
  16959.            find_what = FIND_PREV;
  16960.            find_what_given = TRUE;
  16961.          }
  16962.        }
  16963.        else if (EQUAL(temp,"FIRST")) {
  16964.          if (find_what_given) finderror = TRUE;
  16965.          else {
  16966.            find_what = FIND_FIRST;
  16967.            find_what_given = TRUE;
  16968.          }
  16969.        }
  16970.        else if (EQUAL(temp,"LAST")) {
  16971.          if (find_what_given) finderror = TRUE;
  16972.          else {
  16973.            find_what = FIND_LAST;
  16974.            find_what_given = TRUE;
  16975.          }
  16976.        }
  16977.        else if (EQUAL(temp,"ALL")) {
  16978.          if (find_what_given) finderror = TRUE;
  16979.          else {
  16980.            find_what = FIND_ALL;
  16981.            find_what_given = TRUE;
  16982.          }
  16983.        }
  16984.        else if (EQUAL(temp,"CHARS")) {
  16985.          if (find_type_given) finderror = TRUE;
  16986.          else {
  16987.            find_type = FIND_CHARS;
  16988.            find_type_given = TRUE;
  16989.          }
  16990.        }
  16991.        else if (EQUAL(temp,"WORD")) {
  16992.          if (find_type_given) finderror = TRUE;
  16993.          else {
  16994.            find_type = FIND_WORD;
  16995.            find_type_given = TRUE;
  16996.          }
  16997.        }
  16998.        else if (EQUAL(temp,"PREFIX") || EQUAL(temp,"PRE")) {
  16999.          if (find_type_given) finderror = TRUE;
  17000.          else {
  17001.            find_type = FIND_PREFIX;
  17002.            find_type_given = TRUE;
  17003.          }
  17004.        }
  17005.        else if (EQUAL(temp,"SUFFIX") || EQUAL(temp,"SUF")) {
  17006.          if (find_type_given) finderror = TRUE;
  17007.          else {
  17008.            find_type = FIND_SUFFIX;
  17009.            find_type_given = TRUE;
  17010.          }
  17011.        }
  17012.        else if (*(temp+strspn(temp,"0123456789")) == '\0') {
  17013.          if (find_left_bound_given) {
  17014.            if (find_right_bound_given) finderror = TRUE;
  17015.            else {
  17016.              find_right_bound = atoi(temp);
  17017.              if (find_right_bound > bp->maxlen) out_of_bounds = TRUE;
  17018.              find_right_bound_given = TRUE;
  17019.            }
  17020.          }
  17021.          else {
  17022.            find_left_bound  = atoi(temp);
  17023.              if (find_right_bound < 1) out_of_bounds = TRUE;
  17024.            find_left_bound_given = TRUE;
  17025.          }
  17026.        }
  17027.        else {
  17028.          if (find_string_given) finderror = TRUE;
  17029.          else {
  17030.            strcpy(find_string,op);
  17031.            find_form = ff;
  17032.            find_string_given = TRUE;
  17033.          }
  17034.        }
  17035.      }
  17036.    }
  17037.  }
  17038.  
  17039.  if (out_of_bounds) {
  17040.    ERR2("Invalid bound; Bounds must lie between 1 and %d", bp->maxlen);
  17041.    return FALSE;
  17042.  }
  17043.  if (finderror) {
  17044.    ERR1("Put string in quotes; Conflicting or unknown parameter.");
  17045.    return FALSE;
  17046.  }
  17047.  len = strlen(find_string);
  17048.  if (find_string_given) bp->find_hit_end = FALSE;
  17049.  if (find_left_bound_given && find_right_bound_given
  17050.      && find_left_bound > find_right_bound) {
  17051.    n = find_left_bound;
  17052.    find_left_bound = find_right_bound;
  17053.    find_right_bound = n;
  17054.  }
  17055.  else if (find_left_bound_given && !find_right_bound_given) {
  17056.    find_right_bound = find_left_bound + len - 1;
  17057.  }
  17058.  if (find_string_given) {
  17059.    switch (find_form) {
  17060.      case FIND_UNQUOTED:  find_trans = FIND_CAPS;    break;
  17061.      case FIND_QUOTED:    find_trans = FIND_CAPS;    break;
  17062.      case FIND_C:         find_trans = FIND_ASIS;    break;
  17063.      case FIND_T:         find_trans = FIND_CAPS;    break;
  17064.      case FIND_P:         find_trans = FIND_GENERIC; break;
  17065.      case FIND_X:         find_trans = FIND_HEX;
  17066.         if (len % 2 != 0) {
  17067.           ERR1("Odd number of characters in hex string.");
  17068.           return FALSE;
  17069.         }
  17070.         if (len != strspn(find_string,"0123456789abcdefABCDEF")) {
  17071.           ERR1("Invalid (non-hex) characters in hex string.");
  17072.           return FALSE;
  17073.         }
  17074.         for (p = find_string, q = find_string; *p; p += 2, *q++) {
  17075.           sprintf(temp,"0x%2.2s",p);
  17076.           sscanf(temp,"%x",&n);
  17077.           *q = (char)n;
  17078.         }
  17079.         *q = '\0';
  17080.         len = strlen(find_string);
  17081.         break;
  17082.    }
  17083.  }
  17084.  
  17085.  /* Store parameters for next Repeat Find operation. */
  17086.  
  17087.  strcpy(gp->text_find_string,find_string);
  17088.  switch (find_what) {
  17089.    case FIND_PREV:
  17090.    case FIND_LAST:  gp->text_find_what = FIND_PREV; break;
  17091.    default:         gp->text_find_what = FIND_NEXT; break;
  17092.  }
  17093.  gp->text_find_type        = find_type;
  17094.  gp->text_find_trans       = find_trans;
  17095.  gp->text_find_left_bound  = find_left_bound;
  17096.  gp->text_find_right_bound = find_right_bound;
  17097.  
  17098.  if (!*find_string) {
  17099.    ERR1("A null string is not allowed for the FIND command.");
  17100.    return FALSE;
  17101.  }
  17102.  
  17103.  if (bp->total == 0) {
  17104.    ERR1("There is no text to search.");
  17105.    return FALSE;
  17106.  }
  17107.  
  17108.  strcpy(bp->zcmd,"");
  17109.  
  17110.  switch (find_type) {
  17111.    case FIND_CHARS:   show_type = "Chars";  break;
  17112.    case FIND_WORD:    show_type = "Word";   break;
  17113.    case FIND_PREFIX:  show_type = "Prefix"; break;
  17114.    case FIND_SUFFIX:  show_type = "Suffix"; break;
  17115.    default:           show_type = "Text";   break;
  17116.  }
  17117.  
  17118.  switch (find_trans) {
  17119.    case FIND_ASIS:    strcpy(show_string+0,"C'");
  17120.                       strcpy(show_string+2,find_string);
  17121.                       strcat(show_string,"'");
  17122.                       break;
  17123.    case FIND_GENERIC: strcpy(show_string+0,"P'");
  17124.                       strcpy(show_string+2,find_string);
  17125.                       strcat(show_string,"'");
  17126.                       break;
  17127.    case FIND_HEX:     strcpy(show_string+0,"X'");
  17128.                       for (p=find_string,q=show_string+2;*p;p++,q+=2) {
  17129.                         sprintf(q,"%2.2X",*p);
  17130.                       }
  17131.                       strcat(show_string,"'");
  17132.                       break;
  17133.    case FIND_CAPS:
  17134.    default:           strcpy(show_string+0,"'");
  17135.                       strcpy(show_string+1,find_string);
  17136.                       strcat(show_string,"'");
  17137.                       break;
  17138.  }
  17139.  
  17140.  switch (find_trans) {
  17141.    case FIND_CAPS:
  17142.         uppercase_in_place(find_string);
  17143.         break;
  17144.    case FIND_GENERIC:
  17145.         ERR1("The P'string' generic format is not supported.");
  17146.         return FALSE;
  17147.  }
  17148.  
  17149.  hit_end = bp->find_hit_end;
  17150.  findlen = strlen(find_string);
  17151.  
  17152.  if (find_what == FIND_ALL) {
  17153.    bp->find_count = 0;
  17154.    if (!find_it(gp,bp,find_string,findlen,
  17155.                                   find_type,FIND_FIRST,find_trans,
  17156.                                   find_left_bound, find_right_bound)) {
  17157.      sprintf(shortmsg,"No %s %s found",show_type,show_string);
  17158.      sprintf(longmsg,
  17159.              "%s %s - not found within columns %d to %d",
  17160.              show_type,show_string,find_left_bound,find_right_bound);
  17161.      ERR3("%24s;%s",shortmsg,longmsg);
  17162.      return FALSE;
  17163.    }
  17164.    bp->found_row = bp->find_row;
  17165.    bp->found_col = bp->find_col;
  17166.    bp->find_count = 1;
  17167.    while (find_it(gp,bp,find_string,findlen,
  17168.                         find_type,FIND_ALL,find_trans,
  17169.                         find_left_bound, find_right_bound)) {
  17170.          bp->find_count++;
  17171.    }
  17172.    bp->find_hit_end = FALSE;
  17173.  }
  17174.  else {
  17175.    if (!find_it(gp,bp,find_string,findlen,
  17176.                                   find_type,find_what,find_trans,
  17177.                                   find_left_bound, find_right_bound)) {
  17178.      if (hit_end) {
  17179.        sprintf(shortmsg,"No %s %s found",show_type,show_string);
  17180.        sprintf(longmsg,
  17181.                "%s %s - not found within columns %d to %d",
  17182.                show_type,show_string,find_left_bound,find_right_bound);
  17183.        ERR3("%24s;%s",shortmsg,longmsg);
  17184.        return FALSE;
  17185.      }
  17186.      else if (gp->text_find_what == FIND_PREV) {
  17187.        sprintf(shortmsg,"Top of data reached");
  17188.        sprintf(longmsg,
  17189.             "%s %s not found.  Use RFIND to continue from bottom.",
  17190.              show_type, show_string);
  17191.        ERR3("%24s;%s",shortmsg,longmsg);
  17192.      }
  17193.      else {
  17194.        sprintf(shortmsg,"Bottom of data reached");
  17195.        sprintf(longmsg,
  17196.                "%s %s not found.  Use RFIND to continue from top.",
  17197.              show_type, show_string);
  17198.        ERR3("%24s;%s",shortmsg,longmsg);
  17199.      }
  17200.      return FALSE;
  17201.    }
  17202.    bp->found_row = bp->find_row;
  17203.    bp->found_col = bp->find_col;
  17204.  }
  17205.  if (bp->found_row + 1 < bp->top
  17206.   || bp->found_row + 1 >= bp->top + bp->lvl - bp->cols) {
  17207.    bp->top = bp->found_row + 1 - 1;
  17208.    if (bp->top < 0) bp->top = 0;
  17209.  }
  17210.  if (bp->found_col < bp->coloff) {
  17211.    bp->coloff = bp->found_col;
  17212.    *bp->cols_line = '\0';
  17213.  }
  17214.  else if (bp->found_col+len > bp->coloff+80) {
  17215.    bp->coloff = bp->found_col + len - 80;
  17216.    if (bp->coloff < 0) bp->coloff = 0;
  17217.    *bp->cols_line = '\0';
  17218.  }
  17219.  strcpy(bp->cursor, "GGBDYNA");
  17220.  bp->csrpos = 80 * (bp->found_row - bp->top+bp->cols + 1)
  17221.               + bp->found_col - bp->coloff + 1;
  17222.  bp->found_left = bp->csrpos;
  17223.  bp->found_right = bp->found_left + len;
  17224.  bp->reinit_browse = TRUE;
  17225.  
  17226.  if (find_what == FIND_ALL) {
  17227.    sprintf(shortmsg,"%d %s %s",bp->find_count,show_type,show_string);
  17228.    sprintf(longmsg,
  17229.            "%s %s found %d times within columns %d to %d",
  17230.            show_type,show_string,bp->find_count,
  17231.            find_left_bound,find_right_bound);
  17232.    WARN3("%24s;%s",shortmsg,longmsg);
  17233.  }
  17234.  else {
  17235.    sprintf(shortmsg,"%s %s found",show_type,show_string);
  17236.    sprintf(longmsg,
  17237.            "Search for %s %s within columns %d to %d was successful",
  17238.            show_type,show_string, find_left_bound,find_right_bound);
  17239.    WARN3("%24s;%s",shortmsg,longmsg);
  17240.  }
  17241.  bp->find_row = bp->found_row;
  17242.  bp->find_col = bp->found_col;
  17243.  return TRUE;
  17244. }
  17245.  
  17246. /************ Fill browse dynamic area. *******************************/
  17247.  
  17248. static void
  17249. fill_browse_dynamic_area(gp,bp)
  17250. RGGCB              *gp;
  17251. Rstruc browser     *bp;
  17252. {
  17253.  struct textline  **tpp  = NULL;
  17254.  register char     *cp   = NULL;
  17255.  register char     *p;
  17256.  char              *q;
  17257.  char              *r;
  17258.  int                i;
  17259.  int                j;
  17260.  char               temp[12];
  17261.  
  17262.  static char  top_of_data_line[81] = "\
  17263. ********************************* Top of data \
  17264. **********************************";
  17265.  
  17266.  static char  bottom_of_data_line[81] = "\
  17267. ******************************** Bottom of data \
  17268. ********************************";
  17269.  
  17270.  bp->lastpos = bp->bda + bp->size;
  17271.  bp->total = bp->thp->text_line_count;
  17272.  memset(bp->bda,' ',bp->size);
  17273.  
  17274.  if      (bp->more_rows == -MAX_INT)
  17275.          bp->top = 0;
  17276.  else if (bp->more_rows == MAX_INT)
  17277.          bp->top = bp->total + 2 - bp->lvl + bp->cols;
  17278.  else    bp->top += bp->more_rows;
  17279.  
  17280.  if (bp->top < 0) bp->top = 0;
  17281.  if (bp->top > bp->total) bp->top = bp->total + 1;
  17282.  i  = bp->top;
  17283.  p  = bp->bda;
  17284.  
  17285.  if (bp->cols > 0) {
  17286.    if (!*bp->cols_line) {
  17287.      for (j=bp->coloff+1,r=bp->cols_line; j<=bp->coloff+80; j++,r++) {
  17288.        if (j%10 == 0) {
  17289.          sprintf(temp,"%d",j%100);
  17290.          *r = temp[0];
  17291.        }
  17292.        else if (j%5 == 0) *r = '+';
  17293.        else *r = '-';
  17294.      }
  17295.    }
  17296.    memcpy(p,bp->cols_line,80);
  17297.    p += 80;
  17298.  }
  17299.  
  17300.  if (i == 0) {
  17301.    memcpy(p,top_of_data_line,80);
  17302.    p += 80;
  17303.    i++;
  17304.  }
  17305.  
  17306.  bp->firstpos = p;
  17307.  
  17308.  for (tpp=&bp->tv[i-1];i<=bp->total && p<bp->lastpos;i++,tpp++,p+=80) {
  17309.    if ((*tpp)->tab_expanded_text_length > bp->coloff) {
  17310.      cp = (*tpp)->tab_expanded_text + bp->coloff;
  17311.      for (j = 0, q = p; *cp && j < 80; j++, q++, cp++) {
  17312.        if (*cp > 0xf9 || *cp < 0x40) *q = gp->text_dispchar;
  17313.        else *q = *cp;
  17314.      }
  17315.    }
  17316.  }
  17317.  
  17318.  if (p < bp->lastpos) memcpy(p,bottom_of_data_line,80);
  17319.  
  17320.  return;
  17321. }
  17322.  
  17323. /************ Highlight browse text. **********************************/
  17324.  
  17325. static void
  17326. highlight_browse_text(gp,bp)
  17327. RGGCB              *gp;
  17328. Rstruc browser     *bp;
  17329. {
  17330.  char              *p;
  17331.  
  17332.  bp->highlighted = FALSE;
  17333.  
  17334.  if (bp->found_left) {
  17335.    if (EQUAL(bp->cursor,"GGBDYNA")) {
  17336.      for (p = bp->bda + bp->found_left - 1; p >= bp->firstpos; p--) {
  17337.        if (*p == ' ') {
  17338.          *p = DATAOUT_HIGH;
  17339.          bp->highlighted = TRUE;
  17340.          break;
  17341.        }
  17342.      }
  17343.      for (p = bp->bda + bp->found_right - 1; p <= bp->lastpos; p++) {
  17344.       if (*p == ' ') {
  17345.         *p = DATAOUT_LOW;
  17346.          bp->highlighted = TRUE;
  17347.          break;
  17348.        }
  17349.      }
  17350.    }
  17351.  }
  17352.  
  17353.  bp->found_left = 0;
  17354.  bp->found_right = 0;
  17355.  
  17356.  return;
  17357. }
  17358.  
  17359. /************ Display browse data. ************************************/
  17360.  
  17361. static void
  17362. display_browse_data(gp,bp)
  17363. RGGCB              *gp;
  17364. Rstruc browser     *bp;
  17365. {
  17366.  struct cmddesc    *cdp;
  17367.  char              *cp;
  17368.  char              *operands;
  17369.  int                displayrc;
  17370.  int                zscrolln;
  17371.  int                leftcol;
  17372.  int                rightcol;
  17373.  int                command_index;
  17374.  Bool               command_processed_ok;
  17375.  Bool               is_max;
  17376.  Bool               is_scroll_word;
  17377.  Bool               is_scroll_cursor;
  17378.  SCROLL             scroll_amount;
  17379.  char               command    [COMMANDSIZE+1];
  17380.  char               zverb      [16];
  17381.  char               zscrolla   [16];
  17382.  char               longmsg    [73];
  17383.  char               ggbtitle  [129];
  17384.  char               ggbmsg     [81];
  17385.  char               temp1      [81];
  17386.  char               temp2      [81];
  17387.  
  17388. static struct cmddesc browse_commands[] = {
  17389.                           {"L          ",process_locate_command   },
  17390.                           {"LOC        ",process_locate_command   },
  17391.                           {"LOCATE     ",process_locate_command   },
  17392.                           {"F          ",process_find_command     },
  17393.                           {"FIND       ",process_find_command     },
  17394.                           {"RFIND      ",process_find_command     },
  17395.                           {"YRFIND     ",process_find_command     },
  17396.                           {"COL        ",process_cols_command     },
  17397.                           {"COLS       ",process_cols_command     },
  17398.                           {"RES        ",process_reset_command    },
  17399.                           {"RESET      ",process_reset_command    },
  17400.                           {"NOCOL      ",process_reset_command    },
  17401.                           {"NOCOLS     ",process_reset_command    },
  17402.                           {"DISP       ",process_display_command  },
  17403.                           {"DISPL      ",process_display_command  },
  17404.                           {"DISPLAY    ",process_display_command  },
  17405.                           {"EXT        ",process_extract_command  },
  17406.                           {"EXTR       ",process_extract_command  },
  17407.                           {"EXTRACT    ",process_extract_command  },
  17408.                           {"PRT        ",process_print_command    },
  17409.                           {"PRNT       ",process_print_command    },
  17410.                           {"PRINT      ",process_print_command    },
  17411.                           {"INFO       ",process_info_command     },
  17412.                           {"BOOK       ",process_bookmark_command },
  17413.                           {"BOOKMARK   ",process_bookmark_command },
  17414.                           {"OPT        ",process_options_command  },
  17415.                           {"OPTION     ",process_options_command  },
  17416.                           {"OPTIONS    ",process_options_command  },
  17417.                           {"QUIT       ",process_quit_command     },
  17418.                           {"           ",NULL}
  17419.                          };
  17420.  
  17421.  bp->more_rows = 0;
  17422.  bp->override_scroll = FALSE;
  17423.  bp->exit_browse     = FALSE;
  17424.  memset (ggbtitle, '-', 80);
  17425.  strcpy (ggbtitle, "Browse - ");
  17426.  memcpy (ggbtitle + 9, bp->title, strlen(bp->title));
  17427.  *(ggbtitle + 9 + strlen(bp->title)) = ' ';
  17428.  
  17429.  if (!gp->setmsg) {
  17430.    leftcol = bp->coloff + 1;
  17431.    rightcol = bp->coloff + 80;
  17432.    if (bp->top > bp->total) strcpy(temp1,"");
  17433.    else sprintf(temp1, " Line %d of %d,", bp->top, bp->total);
  17434.    if (bp->maxlen <= 80)
  17435.         sprintf(temp2," Cols %d-%d",leftcol,rightcol);
  17436.    else sprintf(temp2," Cols %d-%d of %d",leftcol,rightcol,bp->maxlen);
  17437.    strcpy(ggbmsg,temp1);
  17438.    strcat(ggbmsg,temp2);
  17439.    strcpy (ggbtitle + 79 - strlen(ggbmsg), ggbmsg);
  17440.  }
  17441.  
  17442.  VPUT ("GGBTITLE ",ggbtitle);
  17443.  VPUT ("ZCMD "    ,bp->zcmd);
  17444.  VPUTS("GGBDYNA " ,bp->bda, bp->size);
  17445.  VPUT ("GGBCUR "  ,bp->cursor);
  17446.  IPUT ("GGBPOS "  ,bp->csrpos);
  17447.  VPUT ("YRFIND "  ,"ALIAS FIND");
  17448.  
  17449.  displayrc = GGdispl(gp,"GGMVIEW ");
  17450.  if (displayrc > 0) bp->exit_browse = TRUE;
  17451.  
  17452.  VPUT ("YRFIND "  ,"");
  17453.  VGET ("GGBCUR " ,bp->cursor);
  17454.  VGET ("ZCMD "   ,bp->zcmd);
  17455.  bp->lvl    = IGET("GGBLVL ");
  17456.  bp->csrpos = IGET("GGBPOS ");
  17457.  strip_trailing_in_place(bp->cursor);
  17458.  strcpy(bp->find_cursor, bp->cursor);
  17459.  bp->find_csrpos = bp->csrpos;
  17460.  strcpy(bp->cursor,"");
  17461.  bp->csrpos = 1;
  17462.  if (bp->highlighted) bp->reinit_browse = TRUE;
  17463.  else                 bp->reinit_browse = FALSE;
  17464.  
  17465.  if (*bp->zcmd) {
  17466.    memset(command,' ',COMMANDSIZE);
  17467.    command_index = 0;
  17468.    for (cp = bp->zcmd; *cp && !isspace(*cp); cp++) {
  17469.      if (cp >= bp->zcmd+COMMANDSIZE) {
  17470.        ERR1(
  17471. "Enter EXTract, PRT, BOOKmark, INFO, OPTions, or a browse command.");
  17472.        command_processed_ok = FALSE;
  17473.      }
  17474.      command[command_index++] = toupper(*cp);
  17475.    }
  17476.    while (*cp && isspace(*cp)) cp++;
  17477.    for (cdp=browse_commands; *cdp->command_name != ' '; cdp++) {
  17478.      if (!memcmp(command,cdp->command_name,COMMANDSIZE-1)) {
  17479.        command_processed_ok = (cdp->command_processor)(gp,bp,cp);
  17480.        cdp = NULL;
  17481.        break;
  17482.      }
  17483.    }
  17484.    if (cdp) {
  17485.      ERR1(
  17486. "Enter EXTract, PRT, BOOKmark, INFO, OPTions, or a browse command.");
  17487.      command_processed_ok = FALSE;
  17488.    }
  17489.    if (command_processed_ok) strcpy(bp->zcmd,"");
  17490.  }
  17491.  
  17492.  if (gp->quit || bp->exit_browse) return;
  17493.  
  17494.  /* Check scroll request (ZSCROLLA direction, ZSCROLLN number).
  17495.   * Skip this if something was done by a command which causes
  17496.   * its own pseudo-scrolling to happen (like LOCATE).
  17497.   */
  17498.  
  17499.  if (!bp->override_scroll) {
  17500.  
  17501.    VGET("ZVERB "   , zverb);
  17502.    VGET("ZSCROLLA ", zscrolla);
  17503.    zscrolln = IGET("ZSCROLLN ");
  17504.    is_max = FALSE;
  17505.    is_scroll_word = FALSE;
  17506.    is_scroll_cursor = FALSE;
  17507.  
  17508.    switch (zscrolla[0]) {
  17509.      case 'P':
  17510.      case 'H':
  17511.      case 'D':  is_scroll_word = TRUE;
  17512.                 break;
  17513.      case 'C':  is_scroll_word = TRUE;
  17514.                 is_scroll_cursor = TRUE;
  17515.                 break;
  17516.      case 'M':  is_max = TRUE;
  17517.                 break;
  17518.    }
  17519.  
  17520.    if      (EQUAL(zverb,"DOWN"))  scroll_amount = DOWN;
  17521.    else if (EQUAL(zverb,"UP"))    scroll_amount = UP;
  17522.    else if (EQUAL(zverb,"LEFT"))  scroll_amount = LEFT;
  17523.    else if (EQUAL(zverb,"RIGHT")) scroll_amount = RIGHT;
  17524.    else                           scroll_amount = NO_SCROLL;
  17525.  
  17526.    switch (scroll_amount) {
  17527.      case NO_SCROLL:
  17528.           bp->more_rows = 0;
  17529.           break;
  17530.      case DOWN:
  17531.           if (is_max) bp->more_rows = MAX_INT;
  17532.           else if (is_scroll_word)
  17533.                       bp->more_rows = zscrolln - bp->cols;
  17534.           else        bp->more_rows = zscrolln;
  17535.           bp->reinit_browse = TRUE;
  17536.           break;
  17537.      case UP:
  17538.           if (is_max) bp->more_rows = -MAX_INT;
  17539.           else if (is_scroll_cursor)
  17540.                       bp->more_rows = -zscrolln;
  17541.           else if (is_scroll_word)
  17542.                       bp->more_rows = -zscrolln - bp->cols;
  17543.           else        bp->more_rows = -zscrolln;
  17544.           bp->reinit_browse = TRUE;
  17545.           break;
  17546.      case LEFT:
  17547.           if (is_max) bp->coloff = 0;
  17548.           else        bp->coloff -= zscrolln;
  17549.           if (bp->coloff < 0) bp->coloff = 0;
  17550.           *bp->cols_line = '\0';
  17551.           bp->more_rows = 0;
  17552.           bp->reinit_browse = TRUE;
  17553.           break;
  17554.      case RIGHT:
  17555.           if (is_max) bp->coloff = bp->maxcoloff;
  17556.           else        bp->coloff += zscrolln;
  17557.           if (bp->coloff > bp->maxcoloff) bp->coloff = bp->maxcoloff;
  17558.           *bp->cols_line = '\0';
  17559.           bp->more_rows = 0;
  17560.           bp->reinit_browse = TRUE;
  17561.           break;
  17562.    }
  17563.  }
  17564.  
  17565.  return;
  17566. }
  17567.  
  17568. /****** View text in full screen mode (BROWSE replacement) ***********/
  17569.  
  17570. void
  17571. GGview(gp,ip,texthdrp,title)
  17572. RGGCB               *gp;
  17573. RINFO               *ip;
  17574. TEXTHDR             *texthdrp;
  17575. char                *title;
  17576. {
  17577.  TEXTLINE           *tp;
  17578.  TEXTLINE          **tv;
  17579.  TEXTLINE          **textvector;
  17580.  struct browser     *bp;
  17581.  struct browser      browserstruct;
  17582.  
  17583.  GETMAIN(textvector,TEXTLINE *,texthdrp->text_line_count,"text vector");
  17584.  if (!textvector) {
  17585.    ERR1("Not enough memory to display text.");
  17586.    return;
  17587.  }
  17588.  
  17589.  bp = &browserstruct;
  17590.  CLEAR(bp);
  17591.  bp->ip  = ip;
  17592.  bp->thp = texthdrp;
  17593.  bp->tv  = textvector;
  17594.  strcpy(bp->title,title);
  17595.  bp->more_rows = -MAX_INT;   /* set initial request to scroll up max */
  17596.  bp->top       = 0;
  17597.  bp->find_row  = -1;
  17598.  bp->find_col  = -1;
  17599.  bp->csrpos    = 1;
  17600.  strcpy(bp->cursor,"");
  17601.  bp->reinit_browse = TRUE;
  17602.  
  17603.  /* Collect text line pointers, skipping suppressed lines. */
  17604.  
  17605.  bp->maxlen = 0;
  17606.  for (tp=texthdrp->first_text_line, tv=textvector; tp; tp=tp->next) {
  17607.    if (tp->text_length >= 0) {
  17608.      *(tv++) = tp;
  17609.      if (bp->maxlen < tp->tab_expanded_text_length)
  17610.          bp->maxlen = tp->tab_expanded_text_length;
  17611.    }
  17612.  }
  17613.  bp->maxcoloff = bp->maxlen - 80;
  17614.  if (bp->maxcoloff < 0) bp->maxcoloff = 0;
  17615.  
  17616.  GETMAIN(bp->work, char, bp->maxlen+1, "browse work string");
  17617.  if (!bp->work) return;
  17618.  
  17619.  ISPF("PQUERY PANEL(GGMVIEW) AREANAME(GGBDYNA) DEPTH(GGBDEPTH)");
  17620.  if (gp->ispfrc != 0) return;
  17621.  bp->depth = IGET("GGBDEPTH ");
  17622.  bp->size = bp->depth * 80;
  17623.  GETMAIN(bp->bda, char, bp->size+1, "browse dynamic area");
  17624.  if (!bp->bda) return;
  17625.  
  17626.  if (!gp->text_dispchar) gp->text_dispchar = '.';
  17627.  
  17628.  do {
  17629.    if (bp->reinit_browse) {
  17630.      fill_browse_dynamic_area(gp,bp);
  17631.      highlight_browse_text(gp,bp);
  17632.    }
  17633.    display_browse_data(gp,bp);
  17634.  } while (!gp->quit && !bp->exit_browse);
  17635.  
  17636.  FREEMAIN(bp->work,"browse work string");
  17637.  FREEMAIN(bp->bda, "browse dynamic area");
  17638.  FREEMAIN(textvector, "text vector");
  17639.  
  17640.  return;
  17641. }
  17642.  
  17643. ./ ADD NAME=GGVTX
  17644.  
  17645.  /********************************************************************/
  17646.  /*                                                                  */
  17647.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  17648.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  17649.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  17650.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  17651.  /*                                                                  */
  17652.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  17653.  /* including the implied warranties of merchantability and fitness, */
  17654.  /* are expressly denied.                                            */
  17655.  /*                                                                  */
  17656.  /* Provided this copyright notice is included, this software may    */
  17657.  /* be freely distributed and not offered for sale.                  */
  17658.  /*                                                                  */
  17659.  /* Changes or modifications may be made and used only by the maker  */
  17660.  /* of same, and not further distributed.  Such modifications should */
  17661.  /* be mailed to the author for consideration for addition to the    */
  17662.  /* software and incorporation in subsequent releases.               */
  17663.  /*                                                                  */
  17664.  /********************************************************************/
  17665.  
  17666. #pragma  csect(code,  "GG@VTX  ")
  17667. #pragma  csect(static,"GG$VTX  ")
  17668. #include "gg.h"
  17669.  
  17670. /****** View the lines of text retrieved from the server. ************/
  17671.  
  17672. Bool
  17673. GGvtx(gp,ip,how)
  17674. RGGCB     *gp;
  17675. RINFO     *ip;
  17676. GOHOW      how;
  17677. {
  17678.  TEXTHDR  *texthdrp;
  17679.  char      title [81];
  17680.  
  17681.  switch (how) {
  17682.    case AS_NOTHING: return;
  17683.    default:         break;
  17684.  }
  17685.  
  17686.  texthdrp = (ip ? &ip->thdr : &gp->thdr);
  17687.  
  17688.  if (!ip) sprintf(title, "GopherServer:%s ",gp->ggserver);
  17689.  else     strncpy(title, ip->desc, sizeof(title));
  17690.  
  17691.  GGview(gp,ip,texthdrp,title);
  17692.  
  17693.  return;
  17694. }
  17695.  
  17696. ./ ADD NAME=GGWAIS
  17697.  
  17698.  /********************************************************************/
  17699.  /*                                                                  */
  17700.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  17701.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  17702.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  17703.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  17704.  /*                                                                  */
  17705.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  17706.  /* including the implied warranties of merchantability and fitness, */
  17707.  /* are expressly denied.                                            */
  17708.  /*                                                                  */
  17709.  /* Provided this copyright notice is included, this software may    */
  17710.  /* be freely distributed and not offered for sale.                  */
  17711.  /*                                                                  */
  17712.  /* Changes or modifications may be made and used only by the maker  */
  17713.  /* of same, and not further distributed.  Such modifications should */
  17714.  /* be mailed to the author for consideration for addition to the    */
  17715.  /* software and incorporation in subsequent releases.               */
  17716.  /*                                                                  */
  17717.  /********************************************************************/
  17718.  
  17719. #pragma  csect(code,  "GG@WAIS ")
  17720. #pragma  csect(static,"GG$WAIS ")
  17721. #include "gg.h"
  17722.  
  17723. /****** Gopher WAIS interface. *************************************/
  17724.  
  17725. Bool
  17726. GGwais(gp,ip,how)
  17727. RGGCB   *gp;
  17728. RINFO   *ip;
  17729. GOHOW    how;
  17730. {
  17731.  RCONN  *sp = &gp->gopher_connection;
  17732.  char   *lp;
  17733.  char    ggwaisq [256];
  17734.  
  17735.  strcpy(gp->ggserver,ip->host);     /* Specify server to connect to */
  17736.  strcpy(ggwaisq,"");
  17737.  ISPF("VGET (GGWAISQ) PROFILE");
  17738.  if (GGdispl(gp,"GGMPWAIS") > 0) return FALSE;
  17739.  VGET("GGWAISQ ",ggwaisq);
  17740.  
  17741.  if (!*ip->path) strcpy(gp->gopher_command, ggwaisq);
  17742.  else            sprintf(gp->gopher_command,"%s\t%s",ip->path,ggwaisq);
  17743.  
  17744.  gp->ginfo = ip;
  17745.  
  17746.  if (!GGconn(gp,sp)) return FALSE;  /* Connect to gopher server */
  17747.  GOPHERSEND(gp,sp);                 /* Send socket command */
  17748.  GGclrtx(gp,ip);                    /* Clear text */
  17749.  sp->receiving_text = TRUE;
  17750.  
  17751.  while (GGgsrvl(gp,sp,&lp,CRLF))  {   /* Get server line */
  17752.    if (!lp) break;
  17753.    (void)GGouttx(gp,lp,ip,NO_VALUE);  /* Output text line */
  17754.  }
  17755.  if (sp->time_to_go_home) {
  17756.    WARN2("No data available from server %s.\n",gp->ggserver);
  17757.    return FALSE;
  17758.  }
  17759.  
  17760.  if (sp->connected_to_server) {
  17761.    (void)GGdisc(gp,sp);           /* Disconnect from gopher server */
  17762.  }
  17763.  
  17764.  GGdir(gp,ip,how); /* display entries returned from WAIS server */
  17765.  
  17766.  return TRUE;
  17767.  
  17768. }
  17769.  
  17770. ./ ADD NAME=GGWHOIS
  17771.  
  17772.  /********************************************************************/
  17773.  /*                                                                  */
  17774.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  17775.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  17776.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  17777.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  17778.  /*                                                                  */
  17779.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  17780.  /* including the implied warranties of merchantability and fitness, */
  17781.  /* are expressly denied.                                            */
  17782.  /*                                                                  */
  17783.  /* Provided this copyright notice is included, this software may    */
  17784.  /* be freely distributed and not offered for sale.                  */
  17785.  /*                                                                  */
  17786.  /* Changes or modifications may be made and used only by the maker  */
  17787.  /* of same, and not further distributed.  Such modifications should */
  17788.  /* be mailed to the author for consideration for addition to the    */
  17789.  /* software and incorporation in subsequent releases.               */
  17790.  /*                                                                  */
  17791.  /********************************************************************/
  17792.  
  17793. #pragma  csect(code,  "GG@WHOIS")
  17794. #pragma  csect(static,"GG$WHOIS")
  17795. #include "gg.h"
  17796.  
  17797. /****** Gopher WHOIS/FINGER interface. *****************************/
  17798.  
  17799. Bool
  17800. GGwhois(gp,ip,how)
  17801. RGGCB  *gp;
  17802. RINFO  *ip;
  17803. GOHOW   how;
  17804. {
  17805.  RCONN *sp = &gp->gopher_connection;
  17806.  char  *lp;
  17807.  Bool   got_some;
  17808.  char   ggwhoisq [256];
  17809.  
  17810.  strcpy(gp->ggserver,ip->host);     /* Specify server to connect to */
  17811.  strcpy(ggwhoisq,"");
  17812.  ISPF("VGET (GGWHOISQ) PROFILE");
  17813.  if (GGdispl(gp,"GGMPWHOI") > 0) return FALSE;
  17814.  VGET("GGWHOISQ ",ggwhoisq);
  17815.  
  17816.  if (!*ip->path) strcpy(gp->gopher_command, ggwhoisq);
  17817.  else            sprintf(gp->gopher_command,"%s\t%s",ip->path,ggwhoisq);
  17818.  
  17819.  gp->ginfo = ip;
  17820.  
  17821.  if (!GGconn(gp,sp)) return FALSE;   /* Connect to gopher server */
  17822.  GOPHERSEND(gp,sp);                  /* Send socket command */
  17823.  GGclrtx(gp,ip);                     /* Clear text */
  17824.  
  17825.  sp->receiving_text = TRUE;
  17826.  got_some = FALSE;
  17827.  while (GGgsrvl(gp,sp,&lp,CRLF)) {   /* Get server line */
  17828.    if (!lp) break;
  17829.    got_some = TRUE;
  17830.    (void)GGouttx(gp,lp,ip,NO_VALUE); /* Output text line */
  17831.  }
  17832.  
  17833.  if (!got_some) {
  17834.    WARN2("No data available from server %s.\n",gp->ggserver);
  17835.    return FALSE;
  17836.  }
  17837.  
  17838.  if (sp->connected_to_server) {
  17839.    (void)GGdisc(gp,sp);         /* Disconnect from gopher server */
  17840.  }
  17841.  
  17842.  GGvtx(gp,ip,how);      /* display text from WHOIS/FINGER server */
  17843.  
  17844.  return TRUE;
  17845.  
  17846. }
  17847.  
  17848. ./ ADD NAME=GGWTO
  17849.  
  17850.  /********************************************************************/
  17851.  /*                                                                  */
  17852.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  17853.  /*                                                                  */
  17854.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  17855.  /* including the implied warranties of merchantability and fitness, */
  17856.  /* are expressly denied.                                            */
  17857.  /*                                                                  */
  17858.  /* Provided this copyright notice is included, this software may    */
  17859.  /* be freely distributed and not offered for sale.                  */
  17860.  /*                                                                  */
  17861.  /* Changes or modifications may be made and used only by the maker  */
  17862.  /* of same, and not further distributed.  Such modifications should */
  17863.  /* be mailed to the author for consideration for addition to the    */
  17864.  /* software and incorporation in subsequent releases.               */
  17865.  /*                                                                  */
  17866.  /********************************************************************/
  17867.  
  17868. #pragma  csect(code,  "GG@WTO")
  17869. #pragma  csect(static,"GG$WTO")
  17870.  
  17871. #include "gg.h"
  17872. #include "ggsvc.h"
  17873.  
  17874. #define WTOTEXTLENGTH  256
  17875. #define WTOSVC         35
  17876.  
  17877. #define WRITE_TO_PROGRAMMER 1
  17878.  
  17879. int
  17880. GGwto(char    *message)
  17881. {
  17882.  char         *cp;
  17883.  SVC_REGISTER  reg15;
  17884.  SVC_REGISTER  reg0;
  17885.  SVC_REGISTER  reg1;
  17886.  struct        {
  17887.                 short   wtolen;
  17888.                 short   wtodum;
  17889.                 char    wtotext[WTOTEXTLENGTH+1];
  17890.                 char    routecodestuff[9];
  17891.                }        wto;
  17892.  
  17893.  CLEAR(&wto);
  17894.  strncpy(wto.wtotext,message,WTOTEXTLENGTH);
  17895.  wto.wtolen = strlen(wto.wtotext) + 4;
  17896.  wto.wtodum = 0;
  17897.  
  17898. #ifdef WRITE_TO_PROGRAMMER
  17899.  
  17900.  wto.wtodum = 0x8000;
  17901.  cp = wto.wtotext + strlen(wto.wtotext);
  17902.  cp[0] = 0x00;
  17903.  cp[1] = 0x00;
  17904.  cp[2] = 0x00;
  17905.  cp[3] = 0x20;
  17906.  
  17907. #else
  17908.  
  17909.  wto.wtodum = 0;
  17910.  
  17911. #endif
  17912.  
  17913.  
  17914.  reg15 = (SVC_REGISTER) 0;
  17915.  reg0  = (SVC_REGISTER) 0;
  17916.  reg1  = (SVC_REGISTER) &wto;
  17917.  
  17918.  SVC(WTOSVC,®15,®0,®1);
  17919.  
  17920.  return (int)reg15;
  17921.  
  17922. }
  17923.  
  17924. ./ ADD NAME=GGXTX
  17925.  
  17926.  /********************************************************************/
  17927.  /*                                                                  */
  17928.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  17929.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  17930.  /* GOPHER client due to Steve Bacher at Draper Laboratory.          */
  17931.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  17932.  /*                                                                  */
  17933.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  17934.  /* including the implied warranties of merchantability and fitness, */
  17935.  /* are expressly denied.                                            */
  17936.  /*                                                                  */
  17937.  /* Provided this copyright notice is included, this software may    */
  17938.  /* be freely distributed and not offered for sale.                  */
  17939.  /*                                                                  */
  17940.  /* Changes or modifications may be made and used only by the maker  */
  17941.  /* of same, and not further distributed.  Such modifications should */
  17942.  /* be mailed to the author for consideration for addition to the    */
  17943.  /* software and incorporation in subsequent releases.               */
  17944.  /*                                                                  */
  17945.  /********************************************************************/
  17946.  
  17947. #pragma  csect(code,  "GG@XTX  ")
  17948. #pragma  csect(static,"GG$XTX  ")
  17949. #include "gg.h"
  17950.  
  17951. #define XFPUTC(A)     gp->extract_write_error = (fputc((A),xfp) == EOF)
  17952.  
  17953. #define XFWRITE(A,B)  fwrite((A),(B),1,xfp), \
  17954.                       gp->extract_write_error = (ferror(xfp) != 0)
  17955. #define XWRITE(A)     XFWRITE(A,strlen(A))
  17956.  
  17957. #define NEWLINE       if (ex != BOOKMANAGE_IT) XFPUTC('\n')
  17958.  
  17959. /****** Extract the lines of server text into a data set. ************/
  17960.  
  17961. Bool
  17962. GGxtx(gp,ip,ex)
  17963. RGGCB         *gp;
  17964. RINFO         *ip;
  17965. EXTREQ         ex;
  17966. {
  17967.  FILE         *xfp;
  17968.  TEXTHDR      *thp;
  17969.  TEXTLINE     *tp;
  17970.  EXTRACTION   *ep;
  17971.  char         *cp;
  17972.  int           l;
  17973.  int           linelen;
  17974.  Bool          final;
  17975.  EXTRACTION    the_extraction;
  17976.  
  17977.  thp = (ip && ex != BOOKMARK_IT ? &ip->thdr : &gp->thdr);
  17978.  
  17979.  /* Set article data for message. */
  17980.  
  17981.  if (ip) {
  17982.    IPUT("GGTNUM " ,ip->type);
  17983.    VPUT("GGTSUBJ ",ip->desc);
  17984.  }
  17985.  
  17986.  if (ex == BOOKMANAGE_IT) {
  17987.    xfp = gp->extract_file;
  17988.    ep = &the_extraction;
  17989.    CLEAR(ep);
  17990.    ep->ex = ex;
  17991.    gp->extract_tab_expanding          = ep->tab_expanding;
  17992.    gp->extract_appending              = ep->appending;
  17993.    gp->extract_blank_before_separator = ep->blanking;
  17994.    gp->extract_separator_line         = ep->separator;
  17995.  }
  17996.  else if (gp->extract_file) {
  17997.    ISPF("CONTROL DISPLAY LOCK");
  17998.      switch (ex) {
  17999.        case PRINT_IT: ISPF("DISPLAY PANEL(GGMLPRN2)"); break;
  18000.        default:       ISPF("DISPLAY PANEL(GGMLEXN2)"); break;
  18001.      }
  18002.    xfp = gp->extract_file;
  18003.    ep = gp->extractionp;
  18004.  }
  18005.  else {
  18006.  
  18007.    ep = &the_extraction;
  18008.    CLEAR(ep);
  18009.    switch (ex) {
  18010.      case EXTRACT_IT:  ep->mode = SEQ;
  18011.                        strcpy(ep->panelname,"GGMPEXDS");
  18012.                        break;
  18013.      case PRINT_IT:    ep->mode = JES;
  18014.                        strcpy(ep->panelname,"GGMPPRDS");
  18015.                        break;
  18016.      case BOOKMARK_IT: ep->mode = SEQ;
  18017.                        strcpy(ep->panelname,"GGMPBMDS");
  18018.                        break;
  18019.    }
  18020.    ep->ex = ex;
  18021.  
  18022.    if (ip) VPUT("GGTSUBJ ",ip->desc);
  18023.    else    VPUT("GGTSUBJ ","");
  18024.  
  18025.    if (!((xfp=GGgetds(gp,ep)))) return FALSE;
  18026.  
  18027.    gp->extract_tab_expanding          = ep->tab_expanding;
  18028.    gp->extract_appending              = ep->appending;
  18029.    gp->extract_blank_before_separator = ep->blanking;
  18030.    gp->extract_separator_line         = ep->separator;
  18031.  }
  18032.  
  18033.  gp->extract_write_error = FALSE;
  18034.  gp->extract_close_error = FALSE;
  18035.  
  18036.  /* If a bookmark, then write gopher menu header only if this is
  18037.   * a new data set (not appending).
  18038.   */
  18039.  
  18040.  if (ep->ex == BOOKMARK_IT && !ep->appending) {
  18041.    XWRITE(MENUIDENT);
  18042.    NEWLINE;
  18043.  }
  18044.  
  18045.  /* If append mode, and a separator line was specified, use it. */
  18046.  
  18047.  if (gp->extract_appending) {
  18048.    NEWLINE;
  18049.    if (gp->extract_separator_line && *gp->extract_separator_line) {
  18050.      XWRITE(gp->extract_separator_line);
  18051.      NEWLINE;
  18052.      if (gp->extract_blank_before_separator) {NEWLINE;}
  18053.    }
  18054.  }
  18055.  
  18056.  switch (ex) {
  18057.    case EXTRACT_IT:    linelen = 251;  break;
  18058.    case PRINT_IT:      linelen = 120;  break;
  18059.    case BOOKMARK_IT:   linelen = 251;  break;
  18060.    case BOOKMANAGE_IT: linelen = 4096; break;
  18061.  }
  18062.  
  18063.  for (tp = thp->first_text_line;
  18064.       tp && !gp->extract_write_error;
  18065.       tp = tp->next) {
  18066.    if (tp->text_length == 0) {
  18067.      NEWLINE;
  18068.    }
  18069.    else if (tp->text_length > 0) {
  18070.      if (gp->extract_tab_expanding) {
  18071.        cp = tp->tab_expanded_text;
  18072.        l  = tp->tab_expanded_text_length;
  18073.      }
  18074.      else {
  18075.        cp = tp->text;
  18076.        l  = tp->text_length;
  18077.      }
  18078.      for (; l>0 && !gp->extract_write_error; cp+=linelen, l-=linelen) {
  18079.        XFWRITE(cp,(l > linelen ? linelen : l));
  18080.        NEWLINE;
  18081.      }
  18082.    }
  18083.  }
  18084.  
  18085.  if (!gp->extract_write_error && ferror(xfp))
  18086.     gp->extract_write_error = TRUE;
  18087.  
  18088.  if (ex != BOOKMANAGE_IT) {
  18089.    if (!gp->extract_appending || !gp->extract_file) {
  18090.      switch (ex) {
  18091.        case PRINT_IT:     final = TRUE;  break;
  18092.        default:           final = FALSE; break;
  18093.      }
  18094.      (ep->closer)(gp,ep,xfp,final);   /* Close the file */
  18095.      if (gp->extract_close_error) return FALSE;
  18096.    }
  18097.  }
  18098.  
  18099.  if (!gp->extract_file) {
  18100.    if (gp->extract_write_error) {
  18101.      ERR2("An error occurred writing to %s.", ep->dsname);
  18102.      gp->extract_write_error = TRUE;
  18103.    }
  18104.    else switch (ex) {
  18105.      case EXTRACT_IT:
  18106.           WARN2("Current text extracted into %s.", ep->dsname);
  18107.           break;
  18108.      case PRINT_IT:
  18109.           WARN2("Current text printed to %s.", ep->dsname);
  18110.           break;
  18111.      case BOOKMARK_IT:
  18112.           WARN2("Item stored as bookmark in %s.", ep->dsname);
  18113.           break;
  18114.    }
  18115.  }
  18116.  if (gp->extract_write_error) return FALSE;
  18117.  else return TRUE;
  18118. }
  18119.  
  18120. ./ ADD NAME=XGALLOC
  18121.  
  18122.  /********************************************************************/
  18123.  /*                                                                  */
  18124.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  18125.  /*                                                                  */
  18126.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  18127.  /* including the implied warranties of merchantability and fitness, */
  18128.  /* are expressly denied.                                            */
  18129.  /*                                                                  */
  18130.  /* Provided this copyright notice is included, this software may    */
  18131.  /* be freely distributed and not offered for sale.                  */
  18132.  /*                                                                  */
  18133.  /* Changes or modifications may be made and used only by the maker  */
  18134.  /* of same, and not further distributed.  Such modifications should */
  18135.  /* be mailed to the author for consideration for addition to the    */
  18136.  /* software and incorporation in subsequent releases.               */
  18137.  /*                                                                  */
  18138.  /********************************************************************/
  18139.  
  18140. /*
  18141.  ***********************************************************************
  18142.  *                                                                     *
  18143.  * This is not a main program, nor a subroutine to be linked into an   *
  18144.  * existing program, but a routine which is to be called from a        *
  18145.  * REXX exec as follows:                                               *
  18146.  *                                                                     *
  18147.  *  dsn = "name.of.data.set"  -- or null to create a temporary         *
  18148.  *  dnn = "ddname"            -- or null to generate a unique one      *
  18149.  *  disp = "SHR"              -- or "OLD", "NEW", "FREE" or "DELETE"   *
  18150.  *  msg1 = ""                 -- to be set with an error message       *
  18151.  *  msg2 = ""                 -- to be set with an error message       *
  18152.  *                                                                     *
  18153.  *  address LINKMVS "XGALLOC DSN DDN DISP MSG1 MSG2"                   *
  18154.  *                                                                     *
  18155.  *  In addition to possibly updating the indicated variables, this     *
  18156.  *  routine returns a return code, which becomes the value of "RC".    *
  18157.  *                                                                     *
  18158.  *  The purpose of this routine is to provide a way for REXX execs     *
  18159.  *  to perform allocation and unallocation of data sets from a non-TSO *
  18160.  *  environment.  The LINKMVS (or ATTCHMVS) interface allows it to     *
  18161.  *  update the specified REXX variables by setting values for the      *
  18162.  *  passed parameters without calling REXX routines directly.          *
  18163.  *                                                                     *
  18164.  *  Use of this routine requires TSO/REXX 3.46 or higher.              *
  18165.  *                                                                     *
  18166.  ***********************************************************************
  18167.  */
  18168.  
  18169. #pragma environment(XGALLOC)
  18170. #pragma linkage(ikjeff18,OS)
  18171.  
  18172. #include "gg.h"
  18173. #include "ggsvc.h"
  18174. #include "ggsvc99.h"
  18175.  
  18176. #include <spc.h>
  18177.  
  18178. enum disposition {DISP_SHR,DISP_OLD,DISP_MOD,
  18179.                   DISP_NEW,DISP_KEEP,DISP_DELETE};
  18180.  
  18181. #define set2(A,B)   *(short *)(A) = B
  18182. #define set3(A,B)   memset(A,0,3); *(short *)(A+1) = B
  18183.  
  18184. struct varstring {
  18185.                   short   len;
  18186.                   char    text[1];
  18187.                  };
  18188.  
  18189. typedef struct varstring VARSTRING;
  18190. typedef int              (*ENTRYPOINT) ();
  18191.  
  18192. /*--------------------------------------------------------------------*/
  18193.  
  18194. static ENTRYPOINT
  18195. ggload(char   *module)
  18196. {
  18197.  char          eploc[9];
  18198.  SVC_REGISTER  reg15;
  18199.  SVC_REGISTER  reg0;
  18200.  SVC_REGISTER  reg1;
  18201.  
  18202. #define LOAD_SVC  8
  18203.  
  18204.  memset(eploc,' ',8);
  18205.  memcpy(eploc,module,strlen(module));
  18206.  
  18207.  reg15 = (SVC_REGISTER) 0;
  18208.  reg0  = (SVC_REGISTER) &eploc;
  18209.  reg1  = (SVC_REGISTER) 0;
  18210.  
  18211.  SVC(LOAD_SVC,®15,®0,®1);
  18212.  
  18213.  return (ENTRYPOINT)reg0;
  18214.  
  18215. }
  18216.  
  18217. /*--------------------------------------------------------------------*/
  18218.  
  18219. static void
  18220. allocfail(rc,p99,msg1,msg2)
  18221. int            rc;
  18222. __S99parms    *p99;
  18223. char          *msg1;
  18224. char          *msg2;
  18225. {
  18226.  int           zero = 0;
  18227.  unsigned int  dfid = 0x40320000;
  18228.  struct {
  18229.          short first_level_msg_len;
  18230.          short first_level_msg_offset;
  18231.          char  first_level_msg[251];
  18232.          short second_level_msg_len;
  18233.          short second_level_msg_offset;
  18234.          char  second_level_msg[251];
  18235.         }      dfbuffer;
  18236.  
  18237.  static ENTRYPOINT ikjeff18_pointer = NULL;
  18238.  
  18239.  strcpy(msg1,"");
  18240.  strcpy(msg2,"");
  18241.  
  18242.  if (!ikjeff18_pointer) {
  18243.    ikjeff18_pointer = ggload("IKJEFF18");
  18244.  }
  18245.  
  18246.  dfbuffer.first_level_msg_len = 4;
  18247.  dfbuffer.second_level_msg_len = 4;
  18248.  
  18249.  if (ikjeff18_pointer) {
  18250.    if ((*ikjeff18_pointer)(p99,&rc,&zero,&dfid,&zero,&dfbuffer)) {
  18251.      strcpy(msg1,"IKJEFF18 returned a nonzero return code");
  18252.    }
  18253.    if (dfbuffer.first_level_msg_len > 0) {
  18254.      strncpy(msg1, dfbuffer.first_level_msg,
  18255.                    dfbuffer.first_level_msg_len-4);
  18256.    }
  18257.    if (dfbuffer.second_level_msg_len > 0) {
  18258.      strncpy(msg2, dfbuffer.second_level_msg,
  18259.                    dfbuffer.second_level_msg_len-4);
  18260.    }
  18261.  }
  18262.  else {
  18263.    strcpy(msg1,"XGALLOC cannot load IKJEFF18");
  18264.  }
  18265.  return;
  18266. }
  18267.  
  18268. /*--------------------------------------------------------------------*/
  18269.  
  18270. static void
  18271. setmsg(msgvar,string)
  18272. VARSTRING *msgvar;
  18273. char  *string;
  18274. {
  18275.  
  18276.  msgvar->len = strlen(string);
  18277.  memcpy(msgvar->text,string,msgvar->len);
  18278.  return;
  18279. }
  18280.  
  18281. /*--------------------------------------------------------------------*/
  18282.  
  18283. int
  18284. XGALLOC()
  18285. {
  18286.  VARSTRING      **reg1;
  18287.  VARSTRING       *dsnvar;
  18288.  VARSTRING       *ddnvar;
  18289.  VARSTRING       *dispvar;
  18290.  VARSTRING       *msg1var;
  18291.  VARSTRING       *msg2var;
  18292.  int              i;
  18293.  int              rc;
  18294.  int              disp99_1;
  18295.  int              disp99_2;
  18296.  Bool             unal;
  18297.  enum disposition disp;
  18298.  short            primary_allocation    = 0;
  18299.  short            secondary_allocation  = 0;
  18300.  short            directory_blocks      = 0;
  18301.  short            dsorg                 = 0;
  18302.  char             recfm                 = 0;
  18303.  short            lrecl                 = 0;
  18304.  short            blocksize             = 0;
  18305.  __S99parms       stuff99; /* No "struct", despite manual */
  18306.  TEXTUNIT        *return_dsname_tup = NULL;
  18307.  TEXTUNIT        *return_ddname_tup = NULL;
  18308.  TEXTUNIT        *tup [32];
  18309.  TEXTUNIT         tu  [32];
  18310.  char            *lparp;
  18311.  char            *rparp;
  18312.  char             dsname  [81];
  18313.  char             ddname   [9];
  18314.  char             dispname [9];
  18315.  char             member  [81];
  18316.  char             msg1   [256];
  18317.  char             msg2   [256];
  18318.  
  18319.  reg1 = (VARSTRING **)edcxregs(1);
  18320.  
  18321.  dsnvar  = reg1[0];
  18322.  ddnvar  = reg1[1];
  18323.  dispvar = reg1[2];
  18324.  msg1var = reg1[3];
  18325.  msg2var = reg1[4];
  18326.  
  18327.  memset((char *)&stuff99,0,sizeof(__S99parms));
  18328.  strcpy(msg1,"");
  18329.  strcpy(msg2,"");
  18330.  
  18331.  if (dsnvar->len > 56) {
  18332.    setmsg(msg1var,"DSNAME argument cannot be longer than 56");
  18333.    return 16;
  18334.  }
  18335.  if (ddnvar->len > 8) {
  18336.    setmsg(msg1var,"DDNAME argument cannot be longer than 8");
  18337.    return 16;
  18338.  }
  18339.  if (dispvar->len > 8) {
  18340.    setmsg(msg1var,"DISP must be SHR/OLD/MOD/NEW/FREE/KEEP/DELETE");
  18341.    return 16;
  18342.  }
  18343.  
  18344.  strncpy(dsname,dsnvar->text,dsnvar->len);
  18345.  strncpy(ddname,ddnvar->text,ddnvar->len);
  18346.  strncpy(dispname,dispvar->text,dispvar->len);
  18347.  uppercase_in_place(dsname);
  18348.  uppercase_in_place(ddname);
  18349.  uppercase_in_place(dispname);
  18350.  
  18351.  if      (!strcmp(dispname,"SHR"))    disp = DISP_SHR;
  18352.  else if (!strcmp(dispname,"OLD"))    disp = DISP_OLD;
  18353.  else if (!strcmp(dispname,"MOD"))    disp = DISP_MOD;
  18354.  else if (!strcmp(dispname,"NEW"))    disp = DISP_NEW;
  18355.  else if (!strcmp(dispname,"FREE"))   disp = DISP_KEEP;
  18356.  else if (!strcmp(dispname,"KEEP"))   disp = DISP_KEEP;
  18357.  else if (!strcmp(dispname,"DELETE")) disp = DISP_DELETE;
  18358.  else {
  18359.    setmsg(msg1var,"DISP must be SHR/OLD/MOD/NEW/FREE/KEEP/DELETE");
  18360.    return 16;
  18361.  }
  18362.  
  18363.  switch (disp) {
  18364.    case DISP_SHR:     unal=FALSE; disp99_1=SHR; disp99_2=KEEP; break;
  18365.    case DISP_OLD:     unal=FALSE; disp99_1=OLD; disp99_2=KEEP; break;
  18366.    case DISP_MOD:     unal=FALSE; disp99_1=MOD; disp99_2=CATLG; break;
  18367.    case DISP_NEW:     unal=FALSE; disp99_1=NEW; disp99_2=CATLG; break;
  18368.    case DISP_KEEP:    unal=TRUE; disp99_2=KEEP; break;
  18369.    case DISP_DELETE:  unal=TRUE; disp99_2=DELETE; break;
  18370.  }
  18371.  
  18372.  switch (disp) {
  18373.    case DISP_MOD:
  18374.    case DISP_NEW:
  18375.                  primary_allocation   = 100;
  18376.                  secondary_allocation = primary_allocation;
  18377.                  dsorg                = DSORG_PS;
  18378.                  recfm                = RECFM_VB;
  18379.                  lrecl                = 256;
  18380.                  blocksize            = 23440;
  18381.                  break;
  18382.  }
  18383.  
  18384.  strcpy(member,"");
  18385.  lparp = strchr(dsname,'(');
  18386.  rparp = strchr(dsname,')');
  18387.  if (lparp && rparp && (lparp < rparp) && (*(rparp+1) == '\0')) {
  18388.    *lparp = '\0';            /* makes dsname the seq part only */
  18389.    *rparp = '\0';            /* turns member into a string     */
  18390.    strcpy(member, lparp+1);
  18391.  }
  18392.  
  18393.  stuff99.__S99RBLN   = 20;
  18394.  stuff99.__S99VERB   = unal ? S99VRBUN : S99VRBAL;
  18395.  stuff99.__S99FLAG1  = S99NOCNV << 8;
  18396.  stuff99.__S99ERROR  = 0;
  18397.  stuff99.__S99INFO   = 0;
  18398.  stuff99.__S99TXTPP  = tup;
  18399.  stuff99.__S99FLAG2  = 0;
  18400.  
  18401.  for (i=0; i<32; i++) tup[i] = &tu[i];
  18402.  
  18403.  i = 0;
  18404.  
  18405.  if (*dsname) {
  18406.    tu[i].key        = unal ? DUNDSNAM : DALDSNAM;
  18407.    tu[i].num        = 1;
  18408.    tu[i].ent.len    = strlen(dsname);
  18409.    copy_uppercase(tu[i].ent.prm,dsname);
  18410.    i++;
  18411.  }
  18412.  else if (!unal) {
  18413.    tu[i].key        = DALRTDSN;
  18414.    tu[i].num        = 1;
  18415.    tu[i].ent.len    = 44;
  18416.    memset(tu[i].ent.prm,' ',44);
  18417.    return_dsname_tup = &tu[i];
  18418.    i++;
  18419.  }
  18420.  if (*member) {
  18421.    tu[i].key        = DALMEMBR;
  18422.    tu[i].num        = 1;
  18423.    tu[i].ent.len    = strlen(member);
  18424.    copy_uppercase(tu[i].ent.prm,member);
  18425.    i++;
  18426.  }
  18427.  if (*ddname) {
  18428.    tu[i].key        = unal ? DUNDDNAM : DALDDNAM;
  18429.    tu[i].num        = 1;
  18430.    tu[i].ent.len    = strlen(ddname);
  18431.    copy_uppercase(tu[i].ent.prm,ddname);
  18432.    i++;
  18433.    if (!unal) {
  18434.      tu[i].key      = DALPERMA;
  18435.      tu[i].num      = 0;
  18436.      i++;
  18437.    }
  18438.  }
  18439.  else if (!unal) {
  18440.    tu[i].key        = DALRTDDN;
  18441.    tu[i].num        = 1;
  18442.    tu[i].ent.len    = 8;
  18443.    memset(tu[i].ent.prm,' ',8);
  18444.    return_ddname_tup = &tu[i];
  18445.    i++;
  18446.  }
  18447.  if (unal) {
  18448.    tu[i].key        = DUNUNALC;
  18449.    tu[i].num        = 0;
  18450.    i++;
  18451.  }
  18452.  else {
  18453.    tu[i].key        = DALSTATS;
  18454.    tu[i].num        = 1;
  18455.    tu[i].ent.len    = 1;
  18456.    tu[i].ent.prm[0] = disp99_1;
  18457.    i++;
  18458.    tu[i].key        = DALNDISP;
  18459.    tu[i].num        = 1;
  18460.    tu[i].ent.len    = 1;
  18461.    tu[i].ent.prm[0] = disp99_2;
  18462.    i++;
  18463.  }
  18464.  if (recfm) {
  18465.    tu[i].key        = DALRECFM;
  18466.    tu[i].num        = 1;
  18467.    tu[i].ent.len    = 1;
  18468.    tu[i].ent.prm[0] = recfm;
  18469.    i++;
  18470.  }
  18471.  if (lrecl) {
  18472.    tu[i].key        = DALLRECL;
  18473.    tu[i].num        = 1;
  18474.    tu[i].ent.len    = 2;
  18475.    set2(tu[i].ent.prm,lrecl);
  18476.    i++;
  18477.  }
  18478.  if (blocksize) {
  18479.    tu[i].key        = DALBLKSZ;
  18480.    tu[i].num        = 1;
  18481.    tu[i].ent.len    = 2;
  18482.    set2(tu[i].ent.prm,blocksize);
  18483.    i++;
  18484.  }
  18485.  if (blocksize) {
  18486.    tu[i].key        = DALBLKLN;
  18487.    tu[i].num        = 1;
  18488.    tu[i].ent.len    = 3;
  18489.    set3(tu[i].ent.prm,blocksize);
  18490.    i++;
  18491.  }
  18492.  if (primary_allocation) {
  18493.    tu[i].key        = DALPRIME;
  18494.    tu[i].num        = 1;
  18495.    tu[i].ent.len    = 3;
  18496.    set3(tu[i].ent.prm,primary_allocation);
  18497.    i++;
  18498.  }
  18499.  if (secondary_allocation) {
  18500.    tu[i].key        = DALSECND;
  18501.    tu[i].num        = 1;
  18502.    tu[i].ent.len    = 3;
  18503.    set3(tu[i].ent.prm,secondary_allocation);
  18504.    i++;
  18505.  }
  18506.  if (dsorg) {
  18507.    tu[i].key        = DALDSORG;
  18508.    tu[i].num        = 1;
  18509.    tu[i].ent.len    = 2;
  18510.    set2(tu[i].ent.prm,dsorg);
  18511.    i++;
  18512.  }
  18513.  
  18514.  tup[i] = (void *)0x80000000;
  18515.  
  18516.  rc = svc99(&stuff99);
  18517.  
  18518.  if (rc == 0) {
  18519.    if (return_dsname_tup) {
  18520.      memcpy(dsnvar->text,(char *)return_dsname_tup->ent.prm,64);
  18521.      dsnvar->len = return_dsname_tup->ent.len;
  18522.    }
  18523.    if (return_ddname_tup) {
  18524.      memcpy(ddnvar->text,(char *)return_ddname_tup->ent.prm,8);
  18525.      ddnvar->len = return_ddname_tup->ent.len;
  18526.    }
  18527.  }
  18528.  else {
  18529.    allocfail(rc,&stuff99,msg1,msg2);
  18530.  }
  18531.  setmsg(msg1var,msg1);
  18532.  setmsg(msg2var,msg2);
  18533.  return rc;
  18534. }
  18535.  
  18536. ./ ADD NAME=XGSLEEP
  18537.  
  18538.  /********************************************************************/
  18539.  /*                                                                  */
  18540.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  18541.  /*                                                                  */
  18542.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  18543.  /* including the implied warranties of merchantability and fitness, */
  18544.  /* are expressly denied.                                            */
  18545.  /*                                                                  */
  18546.  /* Provided this copyright notice is included, this software may    */
  18547.  /* be freely distributed and not offered for sale.                  */
  18548.  /*                                                                  */
  18549.  /* Changes or modifications may be made and used only by the maker  */
  18550.  /* of same, and not further distributed.  Such modifications should */
  18551.  /* be mailed to the author for consideration for addition to the    */
  18552.  /* software and incorporation in subsequent releases.               */
  18553.  /*                                                                  */
  18554.  /********************************************************************/
  18555.  
  18556. #include <stdio.h>
  18557. #include "gg.h"
  18558.  
  18559. main(int argc, char **argv) {
  18560.  int     seconds = 0;
  18561.  
  18562.  if (argc > 1) seconds = atoi(argv[1]);
  18563.  
  18564.  if (seconds == 0) seconds = 1;
  18565.  
  18566.  return GGsleep(seconds);
  18567.  
  18568. }
  18569.  
  18570. ./ ADD NAME=XGWTO
  18571.  
  18572.  /********************************************************************/
  18573.  /*                                                                  */
  18574.  /* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993    */
  18575.  /*                                                                  */
  18576.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  18577.  /* including the implied warranties of merchantability and fitness, */
  18578.  /* are expressly denied.                                            */
  18579.  /*                                                                  */
  18580.  /* Provided this copyright notice is included, this software may    */
  18581.  /* be freely distributed and not offered for sale.                  */
  18582.  /*                                                                  */
  18583.  /* Changes or modifications may be made and used only by the maker  */
  18584.  /* of same, and not further distributed.  Such modifications should */
  18585.  /* be mailed to the author for consideration for addition to the    */
  18586.  /* software and incorporation in subsequent releases.               */
  18587.  /*                                                                  */
  18588.  /********************************************************************/
  18589.  
  18590. #pragma runopts(noargparse,noredir)
  18591.  
  18592. #include <stdio.h>
  18593. #include "gg.h"
  18594.  
  18595. main(int argc, char **argv) {
  18596.  char   *message;
  18597.  
  18598.  if (argc < 2) message = "(No message)";
  18599.  else message = argv[1];
  18600.  
  18601.  return GGwto(message);
  18602.  
  18603. }
  18604.  
  18605. ./ ENDUP
  18606. ?!
  18607. //PANELS   EXEC MDLOAD,BS='6160',TRK1='5',TRK2='1',TO='PANELS'
  18608. //SYSIN    DD   DATA,DLM='?!'
  18609. ./ ADD NAME=GGM
  18610. )ATTR
  18611. /*                                                                   /*
  18612. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  18613. /*                                                                   /*
  18614. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  18615. /* including the implied warranties of merchantability and fitness,  /*
  18616. /* are expressly denied.                                             /*
  18617. /*                                                                   /*
  18618. /* Provided this copyright notice is included, this software may     /*
  18619. /* be freely distributed and not offered for sale.                   /*
  18620. /*                                                                   /*
  18621. /* Changes or modifications may be made and used only by the maker   /*
  18622. /* of same, and not further distributed.  Such modifications should  /*
  18623. /* be mailed to the author for consideration for addition to the     /*
  18624. /* software and incorporation in subsequent releases.                /*
  18625. /*                                                                   /*
  18626.  ^ TYPE(INPUT) INTENS(HIGH) COLOR(GREEN) CAPS(OFF)
  18627.  ! TYPE(TEXT)  INTENS(HIGH) COLOR(RED)
  18628. )BODY EXPAND(``)
  18629. %-`-`-  MVS Gopher Client -`-`-
  18630. %COMMAND ===>_ZCMD
  18631. +
  18632. %Gopher server host name+(or IP address) %===>_GGHOST
  18633. +
  18634. %Initial path%===>^GGPATH
  18635. %Port number %===>_GGPORT
  18636. +
  18637. +Note:  You may specify a dash%-+as the Gopher server host name if
  18638.         you want to use your own private Gopher data without making
  18639.         a connection to a server.  If you do, you must specify the
  18640.         name of your private Gopher menu in the initial path.
  18641.         This name must be UNQUOTED AND FULLY QUALIFIED.
  18642.         Alternatively, you may allocate your initial Gopher menu
  18643.         to file GGGOPHER.
  18644.  
  18645.         Any menu entries must also specify a dash in the host field;
  18646.         otherwise they will require server access, as usual.
  18647.  
  18648.         To use the REXX interface, you must allocate file GGEXEC to
  18649.         your library of Gopherable REXX execs.
  18650.  
  18651. +Press!END+key to leave this menu.
  18652. )INIT
  18653.  &ZCMD = &Z
  18654.  IF (&GGPORT = &Z) &GGPORT = 70
  18655. )PROC
  18656.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  18657.  VER (&GGHOST,NB)
  18658.  VER (&GGPORT,NUM)
  18659.  VPUT (GGHOST GGPATH GGPORT) PROFILE
  18660. )END
  18661. ./ ADD NAME=GGMCSO
  18662. )ATTR
  18663. /*                                                                   /*
  18664. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  18665. /*                                                                   /*
  18666. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  18667. /* including the implied warranties of merchantability and fitness,  /*
  18668. /* are expressly denied.                                             /*
  18669. /*                                                                   /*
  18670. /* Provided this copyright notice is included, this software may     /*
  18671. /* be freely distributed and not offered for sale.                   /*
  18672. /*                                                                   /*
  18673. /* Changes or modifications may be made and used only by the maker   /*
  18674. /* of same, and not further distributed.  Such modifications should  /*
  18675. /* be mailed to the author for consideration for addition to the     /*
  18676. /* software and incorporation in subsequent releases.                /*
  18677. /*                                                                   /*
  18678.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  18679.        @   TYPE(OUTPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  18680. )BODY
  18681. +
  18682. %Command ===>^ZCMD
  18683. +
  18684. +Enter name to search for:
  18685. +
  18686. @FNAME1             +==>^FVALUE1
  18687. @FNAME2             +==>^FVALUE2
  18688. @FNAME3             +==>^FVALUE3
  18689. @FNAME4             +==>^FVALUE4
  18690. @FNAME5             +==>^FVALUE5
  18691. @FNAME6             +==>^FVALUE6
  18692. @FNAME7             +==>^FVALUE7
  18693. @FNAME8             +==>^FVALUE8
  18694. @FNAME9             +==>^FVALUE9
  18695. @FNAME10            +==>^FVALUE10
  18696. @FNAME11            +==>^FVALUE11
  18697. @FNAME12            +==>^FVALUE12
  18698. @FNAME13            +==>^FVALUE13
  18699. @FNAME14            +==>^FVALUE14
  18700.  
  18701. +Press%ENTER+to submit search request.
  18702. +Press%&END (END)+to cancel the request.
  18703. +
  18704. )INIT
  18705.  &ZWINTTL = 'CSO Nameserver User Name Search'
  18706.  &END = PFK(END)
  18707.  .CURSOR = FVALUE1
  18708. )PROC
  18709.  IF  (&ZCMD ^= &Z) .MSG = ISPZ001
  18710.  VPUT (FVALUE1 FVALUE2 FVALUE3 FVALUE4 FVALUE5 FVALUE6 FVALUE7) PROFILE
  18711.  VPUT (FVALUE8 FVALUE9 FVALUE10 FVALUE11 FVALUE12) PROFILE
  18712.  VPUT (FVALUE13 FVALUE14) PROFILE
  18713. )END
  18714. ./ ADD NAME=GGMDIR
  18715. )ATTR
  18716. /*                                                                   /*
  18717. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  18718. /*                                                                   /*
  18719. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  18720. /* including the implied warranties of merchantability and fitness,  /*
  18721. /* are expressly denied.                                             /*
  18722. /*                                                                   /*
  18723. /* Provided this copyright notice is included, this software may     /*
  18724. /* be freely distributed and not offered for sale.                   /*
  18725. /*                                                                   /*
  18726. /* Changes or modifications may be made and used only by the maker   /*
  18727. /* of same, and not further distributed.  Such modifications should  /*
  18728. /* be mailed to the author for consideration for addition to the     /*
  18729. /* software and incorporation in subsequent releases.                /*
  18730. /*                                                                   /*
  18731.  ~ TYPE(INPUT) INTENS(HIGH)  CAPS(OFF) JUST(LEFT)
  18732.  ^ TYPE(INPUT) INTENS(HIGH)  CAPS(OFF) JUST(LEFT)
  18733.  ! TYPE(OUTPUT) INTENS(LOW)  CAPS(OFF) JUST(RIGHT) COLOR(YELLOW)
  18734.  # TYPE(OUTPUT) INTENS(LOW)  CAPS(OFF) JUST(RIGHT) COLOR(BLUE)
  18735.  @ TYPE(OUTPUT) INTENS(HIGH) CAPS(OFF) JUST(RIGHT) COLOR(PINK)
  18736.  ? TYPE(OUTPUT) INTENS(LOW)  CAPS(OFF) JUST(LEFT)  COLOR(TURQ) PAD('.')
  18737.  |  AREA(DYNAMIC) EXTEND(ON) SCROLL(ON)
  18738.  \  AREA(DYNAMIC) EXTEND(OFF) SCROLL(OFF)
  18739.  01 TYPE(DATAOUT) INTENS(LOW)
  18740.  02 TYPE(DATAOUT) INTENS(HIGH)
  18741.  03 TYPE(DATAIN)  INTENS(LOW)
  18742.  04 TYPE(DATAIN)  INTENS(HIGH)
  18743.  05 TYPE(DATAOUT) COLOR(GREEN)
  18744.  06 TYPE(DATAOUT) COLOR(PINK)
  18745.  07 TYPE(DATAOUT) COLOR(RED)
  18746.  08 TYPE(DATAOUT) COLOR(TURQ)
  18747.  09 TYPE(DATAOUT) COLOR(YELLOW)
  18748.  0A TYPE(DATAIN)  COLOR(BLUE)
  18749.  0B TYPE(DATAIN)  COLOR(PINK)
  18750.  0C TYPE(DATAIN)  COLOR(TURQ)
  18751.  0D TYPE(DATAIN)  COLOR(WHITE)
  18752.  0E TYPE(DATAIN)  COLOR(YELLOW)
  18753. )BODY EXPAND(``)
  18754. %&GGGHEAD
  18755. %COMMAND ===>~GGGCMD                                          %SCROLL ===>^GAMT+
  18756. +
  18757. +%S+Select%Q+Query%E+Extract%P+Print%B+Bookmark%I+Info
  18758.  -------------------------------------------------------------------------------
  18759. |GGGDYNA                                                                       |
  18760. )INIT
  18761.  IF (&GAMT = &Z) &GAMT = CSR
  18762.  IF (&GGGCSR ^= 0)
  18763.   .CURSOR = GGGDYNA
  18764.   .CSRPOS = &GGGCSR
  18765. )PROC
  18766.  &GGGLVL = LVLINE(GGGDYNA)
  18767.  VPUT (GAMT) PROFILE
  18768. )END
  18769. ./ ADD NAME=GGMLCONN
  18770. )ATTR
  18771. /*                                                                   /*
  18772. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  18773. /*                                                                   /*
  18774. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  18775. /* including the implied warranties of merchantability and fitness,  /*
  18776. /* are expressly denied.                                             /*
  18777. /*                                                                   /*
  18778. /* Provided this copyright notice is included, this software may     /*
  18779. /* be freely distributed and not offered for sale.                   /*
  18780. /*                                                                   /*
  18781. /* Changes or modifications may be made and used only by the maker   /*
  18782. /* of same, and not further distributed.  Such modifications should  /*
  18783. /* be mailed to the author for consideration for addition to the     /*
  18784. /* software and incorporation in subsequent releases.                /*
  18785. /*                                                                   /*
  18786.  ^ TYPE(TEXT) INTENS(HIGH) COLOR(BLUE) HILITE(REVERSE)
  18787.  @ TYPE(TEXT) INTENS(HIGH) COLOR(PINK)
  18788.  # TYPE(TEXT) INTENS(LOW)  COLOR(TURQ)
  18789.  \ TYPE(TEXT) INTENS(HIGH) COLOR(YELLOW)
  18790.  ! TYPE(TEXT) INTENS(HIGH) COLOR(RED)
  18791.  $ TYPE(TEXT) INTENS(LOW)  COLOR(GREEN)
  18792.  ~ TYPE(TEXT) INTENS(HIGH) COLOR(WHITE)
  18793. )BODY EXPAND(``)
  18794. %-`-`-  MVS Gopher Server Connection -`-`-
  18795. +
  18796. +             Client name: &CLIENT
  18797. +
  18798. +
  18799. +             Connection is in progress for Gopher server at:
  18800.               &SERVER
  18801. +
  18802. +
  18803.                                  % Please wait.
  18804. +
  18805. +
  18806. )INIT
  18807. &CLIENT = '&GGCLIENT (&GGCLIEIP)'
  18808. &SERVER = '&GGSERVER (&GGSERVIP)'
  18809. )PROC
  18810. )END
  18811. ./ ADD NAME=GGMLDISC
  18812. )ATTR
  18813. /*                                                                   /*
  18814. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  18815. /*                                                                   /*
  18816. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  18817. /* including the implied warranties of merchantability and fitness,  /*
  18818. /* are expressly denied.                                             /*
  18819. /*                                                                   /*
  18820. /* Provided this copyright notice is included, this software may     /*
  18821. /* be freely distributed and not offered for sale.                   /*
  18822. /*                                                                   /*
  18823. /* Changes or modifications may be made and used only by the maker   /*
  18824. /* of same, and not further distributed.  Such modifications should  /*
  18825. /* be mailed to the author for consideration for addition to the     /*
  18826. /* software and incorporation in subsequent releases.                /*
  18827. /*                                                                   /*
  18828.  ^ TYPE(TEXT) INTENS(HIGH) COLOR(BLUE) HILITE(REVERSE)
  18829.  @ TYPE(TEXT) INTENS(HIGH) COLOR(PINK)
  18830.  # TYPE(TEXT) INTENS(LOW)  COLOR(TURQ)
  18831.  \ TYPE(TEXT) INTENS(HIGH) COLOR(YELLOW)
  18832.  ! TYPE(TEXT) INTENS(HIGH) COLOR(RED)
  18833.  $ TYPE(TEXT) INTENS(LOW)  COLOR(GREEN)
  18834.  ~ TYPE(TEXT) INTENS(HIGH) COLOR(WHITE)
  18835. )BODY EXPAND(``)
  18836. %-`-`-  MVS Gopher Server Connection -`-`-
  18837. +
  18838. +
  18839. +         Disconnection is in progress from the Gopher server at:
  18840.           &GGSOLDER (&GGSOLDIP)
  18841. +
  18842. +
  18843.                                  % Please wait.
  18844. +
  18845. +
  18846. )INIT
  18847. )PROC
  18848. )END
  18849. ./ ADD NAME=GGMLEXN2
  18850. )ATTR
  18851. /*                                                                   /*
  18852. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  18853. /*                                                                   /*
  18854. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  18855. /* including the implied warranties of merchantability and fitness,  /*
  18856. /* are expressly denied.                                             /*
  18857. /*                                                                   /*
  18858. /* Provided this copyright notice is included, this software may     /*
  18859. /* be freely distributed and not offered for sale.                   /*
  18860. /*                                                                   /*
  18861. /* Changes or modifications may be made and used only by the maker   /*
  18862. /* of same, and not further distributed.  Such modifications should  /*
  18863. /* be mailed to the author for consideration for addition to the     /*
  18864. /* software and incorporation in subsequent releases.                /*
  18865. /*                                                                   /*
  18866.  ^ TYPE(TEXT) INTENS(HIGH) COLOR(BLUE) HILITE(REVERSE)
  18867.  @ TYPE(TEXT) INTENS(HIGH) COLOR(PINK)
  18868.  \ TYPE(TEXT) INTENS(HIGH) COLOR(YELLOW)
  18869.  ! TYPE(TEXT) INTENS(HIGH) COLOR(RED)
  18870.  $ TYPE(TEXT) INTENS(LOW)  COLOR(GREEN)
  18871.  ~ TYPE(TEXT) INTENS(HIGH) COLOR(WHITE)
  18872. )BODY EXPAND(``)
  18873. %-`-`-  MVS Gopher Server Connection -`-`-
  18874. +
  18875. +Description: &GGTSUBJ
  18876. +
  18877. +Extracting to: &GGEXDSN
  18878. +&MEMSTUFF
  18879. +
  18880.                                  % Please wait.
  18881. +
  18882. )INIT
  18883.  IF (&GGEXMEM = &Z) &MEMSTUFF = &Z
  18884.  ELSE               &MEMSTUFF = 'Member: &GGEXMEM'
  18885. )PROC
  18886. )END
  18887. ./ ADD NAME=GGMLPRN2
  18888. )ATTR
  18889. /*                                                                   /*
  18890. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1993     /*
  18891. /*                                                                   /*
  18892. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  18893. /* including the implied warranties of merchantability and fitness,  /*
  18894. /* are expressly denied.                                             /*
  18895. /*                                                                   /*
  18896. /* Provided this copyright notice is included, this software may     /*
  18897. /* be freely distributed and not offered for sale.                   /*
  18898. /*                                                                   /*
  18899. /* Changes or modifications may be made and used only by the maker   /*
  18900. /* of same, and not further distributed.  Such modifications should  /*
  18901. /* be mailed to the author for consideration for addition to the     /*
  18902. /* software and incorporation in subsequent releases.                /*
  18903. /*                                                                   /*
  18904.  ^ TYPE(TEXT) INTENS(HIGH) COLOR(BLUE) HILITE(REVERSE)
  18905.  @ TYPE(TEXT) INTENS(HIGH) COLOR(PINK)
  18906.  \ TYPE(TEXT) INTENS(HIGH) COLOR(YELLOW)
  18907.  ! TYPE(TEXT) INTENS(HIGH) COLOR(RED)
  18908.  $ TYPE(TEXT) INTENS(LOW)  COLOR(GREEN)
  18909.  ~ TYPE(TEXT) INTENS(HIGH) COLOR(WHITE)
  18910. )BODY EXPAND(``)
  18911. %-`-`-  MVS Gopher Server Connection -`-`-
  18912. +
  18913. +Description: &GGTSUBJ
  18914. +
  18915. +Printing to SYSOUT class: &GGEXSCL
  18916. +&MEMSTUFF
  18917. +
  18918.                                  % Please wait.
  18919. +
  18920. )INIT
  18921.  IF (&GGEXMEM = &Z) &MEMSTUFF = &Z
  18922.  ELSE               &MEMSTUFF = 'Member: &GGEXMEM'
  18923. )PROC
  18924. )END
  18925. ./ ADD NAME=GGMLSOCK
  18926. )ATTR
  18927. /*                                                                   /*
  18928. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1993     /*
  18929. /*                                                                   /*
  18930. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  18931. /* including the implied warranties of merchantability and fitness,  /*
  18932. /* are expressly denied.                                             /*
  18933. /*                                                                   /*
  18934. /* Provided this copyright notice is included, this software may     /*
  18935. /* be freely distributed and not offered for sale.                   /*
  18936. /*                                                                   /*
  18937. /* Changes or modifications may be made and used only by the maker   /*
  18938. /* of same, and not further distributed.  Such modifications should  /*
  18939. /* be mailed to the author for consideration for addition to the     /*
  18940. /* software and incorporation in subsequent releases.                /*
  18941. /*                                                                   /*
  18942.  ^ TYPE(TEXT) INTENS(HIGH) COLOR(BLUE) HILITE(REVERSE)
  18943.  @ TYPE(TEXT) INTENS(HIGH) COLOR(PINK)
  18944.  # TYPE(TEXT) INTENS(LOW)  COLOR(TURQ)
  18945.  \ TYPE(TEXT) INTENS(HIGH) COLOR(YELLOW)
  18946.  ! TYPE(TEXT) INTENS(HIGH) COLOR(RED)
  18947.  $ TYPE(TEXT) INTENS(LOW)  COLOR(GREEN)
  18948.  ~ TYPE(TEXT) INTENS(HIGH) COLOR(WHITE)
  18949. )BODY EXPAND(``)
  18950. %-`-`-  MVS Gopher Server Connection -`-`-
  18951. +
  18952. +             Client:  &CLIENT
  18953. +
  18954. +             Connection successful.
  18955. +
  18956. +             Retrieving data from Gopher server at:
  18957.               &SERVER
  18958. +
  18959. +
  18960.                                  % Please wait.
  18961. +
  18962. +
  18963. )INIT
  18964. &CLIENT = '&GGCLIENT (&GGCLIEIP)'
  18965. &SERVER = '&GGSERVER (&GGSERVIP)'
  18966. )PROC
  18967. )END
  18968. ./ ADD NAME=GGMOPT1
  18969. )ATTR
  18970. /*                                                                   /*
  18971. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  18972. /*                                                                   /*
  18973. /* SAS enhancements copyright (c) 1992 SAS Institute, Inc.           /*
  18974. /*                                                                   /*
  18975. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  18976. /* including the implied warranties of merchantability and fitness,  /*
  18977. /* are expressly denied.                                             /*
  18978. /*                                                                   /*
  18979. /* Provided this copyright notice is included, this software may     /*
  18980. /* be freely distributed and not offered for sale.                   /*
  18981. /*                                                                   /*
  18982. /* Changes or modifications may be made and used only by the maker   /*
  18983. /* of same, and not further distributed.  Such modifications should  /*
  18984. /* be mailed to the author for consideration for addition to the     /*
  18985. /* software and incorporation in subsequent releases.                /*
  18986. /*                                                                   /*
  18987. )BODY EXPAND(``)
  18988. %-`-`- GOPHER - Directory Viewing Options -`-`-
  18989. %Command ===>_ZCMD
  18990. +
  18991. +Scroll last selected menu item to top? (YES/NO)%==>_Z  +
  18992. +Put cursor at last selected menu item? (YES/NO)%==>_Z  +
  18993.  
  18994.  
  18995. +Press%ENTER+to change options.  Press%&END+(or type%END+command) when done.
  18996. )INIT
  18997.  .ZVARS  = '(GGSCROLL GGCURSOR)'
  18998.  .CURSOR = ZCMD
  18999.  &END = PFK(END)
  19000.  &ZCMD = &Z
  19001.  VGET (GGSCROLL GGCURSOR) PROFILE
  19002.  &GGSCROLL = TRANS(TRUNC(&GGSCROLL,1)  Y,YES N,NO *,YES)
  19003.  &GGCURSOR = TRANS(TRUNC(&GGCURSOR,1)  Y,YES N,NO *,NO )
  19004. )PROC
  19005.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  19006.  IF (.RESP = ENTER)
  19007.   &GGSCROLL = TRUNC(&GGSCROLL,1)
  19008.   &GGCURSOR = TRUNC(&GGCURSOR,1)
  19009.   VER(&GGSCROLL,NB,LIST,Y,N)
  19010.   VER(&GGCURSOR,NB,LIST,Y,N)
  19011.  VPUT (GGSCROLL GGCURSOR) PROFILE
  19012. )END
  19013. ./ ADD NAME=GGMOPT2
  19014. )ATTR
  19015. /*                                                                   /*
  19016. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  19017. /*                                                                   /*
  19018. /* SAS enhancements copyright (c) 1992 SAS Institute, Inc.           /*
  19019. /*                                                                   /*
  19020. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  19021. /* including the implied warranties of merchantability and fitness,  /*
  19022. /* are expressly denied.                                             /*
  19023. /*                                                                   /*
  19024. /* Provided this copyright notice is included, this software may     /*
  19025. /* be freely distributed and not offered for sale.                   /*
  19026. /*                                                                   /*
  19027. /* Changes or modifications may be made and used only by the maker   /*
  19028. /* of same, and not further distributed.  Such modifications should  /*
  19029. /* be mailed to the author for consideration for addition to the     /*
  19030. /* software and incorporation in subsequent releases.                /*
  19031. /*                                                                   /*
  19032. )BODY EXPAND(``)
  19033. %-`-`- GOPHER - Miscellaneous Options -`-`-
  19034. %Command ===>_ZCMD
  19035. +
  19036. %EXTRACT prompting options:
  19037.  
  19038. +Warning panel before writing over an existing dataset?%==>_Z  +
  19039. +Warning panel before appending to an existing dataset?%==>_Z  +
  19040.  
  19041.  
  19042. +Press%ENTER+to change options.  Press%&END+(or type%END+command) when done.
  19043. )INIT
  19044.  .ZVARS  = '(GGEXTPOW GGEXTPAP)'
  19045.  .CURSOR = ZCMD
  19046.  &END = PFK(END)
  19047.  &ZCMD = &Z
  19048.  VGET (GGEXTPOW GGEXTPAP) PROFILE
  19049.  &GGEXTPOW = TRANS(TRUNC(&GGEXTPOW,1) Y,YES N,NO *,YES)
  19050.  &GGEXTPAP = TRANS(TRUNC(&GGEXTPAP,1) Y,YES N,NO *,YES)
  19051. )PROC
  19052.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  19053.  IF (.RESP = ENTER)
  19054.   &GGEXTPOW = TRUNC(&GGEXTPOW,1)
  19055.   &GGEXTPAP = TRUNC(&GGEXTPAP,1)
  19056.   VER(&GGEXTPOW,NB,LIST,Y,N)
  19057.   VER(&GGEXTPAP,NB,LIST,Y,N)
  19058.  VPUT (GGEXTPOW GGEXTPAP) PROFILE
  19059. )END
  19060. ./ ADD NAME=GGMPBMDS
  19061. )ATTR
  19062. /*                                                                   /*
  19063. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  19064. /*                                                                   /*
  19065. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  19066. /* including the implied warranties of merchantability and fitness,  /*
  19067. /* are expressly denied.                                             /*
  19068. /*                                                                   /*
  19069. /* Provided this copyright notice is included, this software may     /*
  19070. /* be freely distributed and not offered for sale.                   /*
  19071. /*                                                                   /*
  19072. /* Changes or modifications may be made and used only by the maker   /*
  19073. /* of same, and not further distributed.  Such modifications should  /*
  19074. /* be mailed to the author for consideration for addition to the     /*
  19075. /* software and incorporation in subsequent releases.                /*
  19076. /*                                                                   /*
  19077.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  19078. )BODY WINDOW(77,10)
  19079. +
  19080. %Command ===>^ZCMD
  19081. +
  19082. %&SUBJECT
  19083. +
  19084. +Bookmark data set ===>_GGBMDSN
  19085.  
  19086. +(Note: Data set must be RECFM=VB, LRECL=259, BLKSIZE=6233.)
  19087.  
  19088. +Press%&END (END)+to cancel the bookmark request.
  19089. )INIT
  19090.  .CURSOR = GGBMDSN
  19091.  &ZWINTTL = 'Append bookmark'
  19092.  &SUBJECT = '&GGTSUBJ'
  19093.  &END = PFK(END)
  19094.  &ZCMD = &Z
  19095.  VGET (GGBMDSN) PROFILE
  19096.  IF (&GGBMDSN = &Z) &GGBMDSN = 'GOPHER.BOOKMARK'
  19097. )PROC
  19098.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  19099.  VER(&GGBMDSN,NB,DSNAME)
  19100.  VPUT (GGBMDSN) PROFILE
  19101. )END
  19102. ./ ADD NAME=GGMPCSO
  19103. )ATTR
  19104. /*                                                                   /*
  19105. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  19106. /*                                                                   /*
  19107. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  19108. /* including the implied warranties of merchantability and fitness,  /*
  19109. /* are expressly denied.                                             /*
  19110. /*                                                                   /*
  19111. /* Provided this copyright notice is included, this software may     /*
  19112. /* be freely distributed and not offered for sale.                   /*
  19113. /*                                                                   /*
  19114. /* Changes or modifications may be made and used only by the maker   /*
  19115. /* of same, and not further distributed.  Such modifications should  /*
  19116. /* be mailed to the author for consideration for addition to the     /*
  19117. /* software and incorporation in subsequent releases.                /*
  19118. /*                                                                   /*
  19119.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  19120. )BODY WINDOW(58,10)
  19121. +
  19122. %Command ===>^ZCMD
  19123. +
  19124. +Enter name to search for:
  19125. +
  19126. %===>^GGCSOQ
  19127.  
  19128. +Press%ENTER+to submit search request.
  19129. +Press%&END (END)+to cancel the request.
  19130. +
  19131. )INIT
  19132.  &ZWINTTL = 'CSO Nameserver User Name Search'
  19133.  &END = PFK(END)
  19134.  .CURSOR = GGCSOQ
  19135. )PROC
  19136.  IF  (&ZCMD ^= &Z) .MSG = ISPZ001
  19137.  VER (&GGCSOQ,NB)
  19138.  VPUT (GGCSOQ) PROFILE
  19139. )END
  19140. ./ ADD NAME=GGMPDBM
  19141. )ATTR
  19142. /*                                                                   /*
  19143. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  19144. /*                                                                   /*
  19145. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  19146. /* including the implied warranties of merchantability and fitness,  /*
  19147. /* are expressly denied.                                             /*
  19148. /*                                                                   /*
  19149. /* Provided this copyright notice is included, this software may     /*
  19150. /* be freely distributed and not offered for sale.                   /*
  19151. /*                                                                   /*
  19152. /* Changes or modifications may be made and used only by the maker   /*
  19153. /* of same, and not further distributed.  Such modifications should  /*
  19154. /* be mailed to the author for consideration for addition to the     /*
  19155. /* software and incorporation in subsequent releases.                /*
  19156. /*                                                                   /*
  19157.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  19158. )BODY WINDOW(58,13)
  19159. +
  19160. %Command ===>^ZCMD
  19161. +
  19162. +Remove bookmark from data set &GGMDBMDS:
  19163. +
  19164. %&GGMDBMSU
  19165. +
  19166. +Press%ENTER+to update &GGMDBMDS.
  19167. +Press%&END (END)+to cancel the request.
  19168. +
  19169. )INIT
  19170.  .ALARM = YES
  19171.  &ZWINTTL = 'Delete Bookmark'
  19172.  &END = PFK(END)
  19173. )PROC
  19174.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  19175. )END
  19176. ./ ADD NAME=GGMPEXDS
  19177. )ATTR
  19178. /*                                                                   /*
  19179. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  19180. /*                                                                   /*
  19181. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  19182. /* including the implied warranties of merchantability and fitness,  /*
  19183. /* are expressly denied.                                             /*
  19184. /*                                                                   /*
  19185. /* Provided this copyright notice is included, this software may     /*
  19186. /* be freely distributed and not offered for sale.                   /*
  19187. /*                                                                   /*
  19188. /* Changes or modifications may be made and used only by the maker   /*
  19189. /* of same, and not further distributed.  Such modifications should  /*
  19190. /* be mailed to the author for consideration for addition to the     /*
  19191. /* software and incorporation in subsequent releases.                /*
  19192. /*                                                                   /*
  19193.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  19194. )BODY WINDOW(77,16)
  19195. +
  19196. %Command ===>^ZCMD
  19197. +
  19198. %&SUBJECT
  19199. +
  19200. +Save to data set ===>_GGEXDSN
  19201. +Expand tab characters?       ===>_Z  +
  19202.  
  19203. +(Note: Data set will be RECFM=VB, LRECL=259, BLKSIZE=6233.)
  19204.  
  19205. +Append to end of data set?   ===>_Z  +
  19206. +Blank line after separator?  ===>_Z  +
  19207. +Separator line between items (append mode only...blank for none):
  19208. +>^Z                                                                       +<
  19209.  
  19210. +Press%&END (END)+to cancel the extract request.
  19211. )INIT
  19212.  .ZVARS = '(GGEXTAB GGEXAPP GGEXBLK GGEXSEP)'
  19213.  .CURSOR = GGEXDSN
  19214.  &ZWINTTL = 'Extract text'
  19215.  &SUBJECT = '&GGTSUBJ'
  19216.  &END = PFK(END)
  19217.  &ZCMD = &Z
  19218.  VGET (GGEXDSN GGEXTAB GGEXAPP GGEXBLK GGEXSEP) PROFILE
  19219.  &GGEXTAB = TRANS(&GGEXTAB Y,YES N,NO ' ',NO)
  19220.  &GGEXAPP = TRANS(&GGEXAPP Y,YES N,NO ' ',NO)
  19221.  &GGEXBLK = TRANS(&GGEXBLK Y,YES N,NO ' ',NO)
  19222. )PROC
  19223.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  19224.  VER(&GGEXDSN,NB,DSNAME)
  19225.  &GGEXTAB = TRUNC(&GGEXTAB,1)
  19226.  VER(&GGEXTAB,NB,LIST,Y,N)
  19227.  &GGEXAPP = TRUNC(&GGEXAPP,1)
  19228.  VER(&GGEXAPP,NB,LIST,Y,N)
  19229.  &GGEXBLK = TRUNC(&GGEXBLK,1)
  19230.  VER(&GGEXBLK,NB,LIST,Y,N)
  19231.  VPUT (GGEXDSN GGEXTAB GGEXAPP GGEXBLK GGEXSEP) PROFILE
  19232. )END
  19233. ./ ADD NAME=GGMPEXNG
  19234. )ATTR
  19235. /*                                                                   /*
  19236. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  19237. /*                                                                   /*
  19238. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  19239. /* including the implied warranties of merchantability and fitness,  /*
  19240. /* are expressly denied.                                             /*
  19241. /*                                                                   /*
  19242. /* Provided this copyright notice is included, this software may     /*
  19243. /* be freely distributed and not offered for sale.                   /*
  19244. /*                                                                   /*
  19245. /* Changes or modifications may be made and used only by the maker   /*
  19246. /* of same, and not further distributed.  Such modifications should  /*
  19247. /* be mailed to the author for consideration for addition to the     /*
  19248. /* software and incorporation in subsequent releases.                /*
  19249. /*                                                                   /*
  19250.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  19251. )BODY WINDOW(77,14)
  19252. +
  19253. %Command ===>^ZCMD
  19254. +
  19255. +Save to data set ===>_GGEXDSN
  19256.  
  19257. +(Note: Data set will be RECFM=VB, LRECL=259, BLKSIZE=6233.)
  19258.  
  19259. +Append to end of data set?   ===>_Z  +
  19260. +Blank line after separator?  ===>_Z  +
  19261. +Separator line between items (append mode only...blank for none):
  19262. +>^Z                                                                       +<
  19263.  
  19264. +Press%&END (END)+to cancel the extract request.
  19265. )INIT
  19266.  .ZVARS = '(GGEXAPP GGEXBLK GGEXSEP)'
  19267.  .CURSOR = GGEXDSN
  19268.  &ZWINTTL = 'Extract item listing'
  19269.  &END = PFK(END)
  19270.  &ZCMD = &Z
  19271.  VGET (GGEXDSN GGEXAPP GGEXBLK GGEXSEP) PROFILE
  19272.  &GGEXAPP = TRANS(&GGEXAPP Y,YES N,NO ' ',NO)
  19273.  &GGEXBLK = TRANS(&GGEXBLK Y,YES N,NO ' ',NO)
  19274. )PROC
  19275.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  19276.  VER(&GGEXDSN,NB,DSNAME)
  19277.  &GGEXAPP = TRUNC(&GGEXAPP,1)
  19278.  VER(&GGEXAPP,NB,LIST,Y,N)
  19279.  &GGEXBLK = TRUNC(&GGEXBLK,1)
  19280.  VER(&GGEXBLK,NB,LIST,Y,N)
  19281.  VPUT (GGEXDSN GGEXAPP GGEXBLK GGEXSEP) PROFILE
  19282. )END
  19283. ./ ADD NAME=GGMPEXNP
  19284. )ATTR
  19285. /*                                                                   /*
  19286. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  19287. /*                                                                   /*
  19288. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  19289. /* including the implied warranties of merchantability and fitness,  /*
  19290. /* are expressly denied.                                             /*
  19291. /*                                                                   /*
  19292. /* Provided this copyright notice is included, this software may     /*
  19293. /* be freely distributed and not offered for sale.                   /*
  19294. /*                                                                   /*
  19295. /* Changes or modifications may be made and used only by the maker   /*
  19296. /* of same, and not further distributed.  Such modifications should  /*
  19297. /* be mailed to the author for consideration for addition to the     /*
  19298. /* software and incorporation in subsequent releases.                /*
  19299. /*                                                                   /*
  19300.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  19301. )BODY EXPAND(``) WINDOW(77,14)
  19302. +
  19303. %Command ===>^ZCMD
  19304. +
  19305. +Data set name%===>_GGEXPDS
  19306. +Member prefix%===>_GGEXPMP + (item number appended - default is%#+)
  19307.  
  19308. +Note: The dataset must be a PDS (old or new) with RECFM=VB and LRECL=259.
  19309.  
  19310. +Expand tab characters?      %===>_Z  +
  19311.  
  19312. +From item number%===>_GGEXAN1         + (blank for first item in table)
  19313. +To   item number%===>_GGEXAN2         + (blank for last item in table)
  19314.  
  19315. +Press%&END (END)+to cancel the extract request.
  19316. )INIT
  19317.  .ZVARS = '(GGEXTAB)'
  19318.  .CURSOR = ZCMD
  19319.  &ZWINTTL = 'Log text of items to PDS members'
  19320.  &END = PFK(END)
  19321.  &ZCMD = &Z
  19322.  VGET (GGEXPDS GGEXPMP GGEXTAB) PROFILE
  19323.  &GGEXTAB = TRANS(&GGEXTAB Y,YES N,NO ' ',NO)
  19324.  IF (&GGEXPMP = &Z) &GGEXPMP = '#'
  19325.  &GGEXAN1 = &Z
  19326.  &GGEXAN2 = &Z
  19327. )PROC
  19328.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  19329.  &GGEXTAB = TRUNC(&GGEXTAB,1)
  19330.  VER(&GGEXTAB,NB,LIST,Y,N)
  19331.  VER(&GGEXPDS,NB,DSNAME)
  19332.  &TEMP1 = TRUNC(&GGEXPDS,1)
  19333.  &TEMP2 = .TRAIL
  19334.  IF (&TEMP1 = '''')
  19335.   &GGEXDSN = TRUNC(&TEMP2,'''')
  19336.  ELSE
  19337.   &GGEXDSN = '&ZPREFIX..&GGEXPDS'
  19338.   VER(&GGEXPMP,NB,NAME)
  19339.  VER(&GGEXAN1,NUM)
  19340.  VER(&GGEXAN2,NUM)
  19341.  VPUT (GGEXPDS GGEXPMP GGEXTAB) PROFILE
  19342. )END
  19343. ./ ADD NAME=GGMPEXNS
  19344. )ATTR
  19345. /*                                                                   /*
  19346. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  19347. /*                                                                   /*
  19348. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  19349. /* including the implied warranties of merchantability and fitness,  /*
  19350. /* are expressly denied.                                             /*
  19351. /*                                                                   /*
  19352. /* Provided this copyright notice is included, this software may     /*
  19353. /* be freely distributed and not offered for sale.                   /*
  19354. /*                                                                   /*
  19355. /* Changes or modifications may be made and used only by the maker   /*
  19356. /* of same, and not further distributed.  Such modifications should  /*
  19357. /* be mailed to the author for consideration for addition to the     /*
  19358. /* software and incorporation in subsequent releases.                /*
  19359. /*                                                                   /*
  19360.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  19361. )BODY EXPAND(``) WINDOW(77,17)
  19362. +
  19363. %Command ===>^ZCMD
  19364. +
  19365. +Data set name%===>_GGEXSEQ
  19366. +(Note: Data set will be RECFM=VB, LRECL=259, BLKSIZE=6233.)
  19367. +
  19368. +Expand tab characters?      %===>_Z  +
  19369. +
  19370. +Append to end of data set?  %===>_Z  +
  19371. +Blank line after separator? %===>_Z  +
  19372. +Separator line before each item (leave blank for none):
  19373. +>^Z                                                                       +<
  19374.  
  19375. +From item number%===>_GGEXAN1         + (blank for first item in table)
  19376. +To   item number%===>_GGEXAN2         + (blank for last item in table)
  19377.  
  19378. +Press%&END (END)+to cancel the extract request.
  19379. )INIT
  19380.  .ZVARS = '(GGEXTAB GGEXAPP GGEXBLK GGEXSEP)'
  19381.  .CURSOR = ZCMD
  19382.  &ZWINTTL = 'Log text of items to sequential file'
  19383.  &END = PFK(END)
  19384.  &ZCMD = &Z
  19385.  VGET (GGEXSEQ GGEXTAB GGEXAPP GGEXBLK GGEXSEP) PROFILE
  19386.  &GGEXTAB = TRANS(&GGEXTAB Y,YES N,NO ' ',NO)
  19387.  &GGEXAPP = TRANS(&GGEXAPP Y,YES N,NO ' ',NO)
  19388.  &GGEXBLK = TRANS(&GGEXBLK Y,YES N,NO ' ',NO)
  19389.  &GGEXAN1 = &Z
  19390.  &GGEXAN2 = &Z
  19391. )PROC
  19392.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  19393.  VER(&GGEXSEQ,NB,DSNAME)
  19394.  &GGEXDSN = &GGEXSEQ
  19395.  &GGEXTAB = TRUNC(&GGEXTAB,1)
  19396.  VER(&GGEXTAB,NB,LIST,Y,N)
  19397.  &GGEXAPP = TRUNC(&GGEXAPP,1)
  19398.  VER(&GGEXAPP,NB,LIST,Y,N)
  19399.  &GGEXBLK = TRUNC(&GGEXBLK,1)
  19400.  VER(&GGEXBLK,NB,LIST,Y,N)
  19401.  VER(&GGEXAN1,NUM)
  19402.  VER(&GGEXAN2,NUM)
  19403.  VPUT (GGEXSEQ GGEXTAB GGEXAPP GGEXBLK GGEXSEP) PROFILE
  19404. )END
  19405. ./ ADD NAME=GGMPEXNT
  19406. )ATTR
  19407. /*                                                                   /*
  19408. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  19409. /*                                                                   /*
  19410. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  19411. /* including the implied warranties of merchantability and fitness,  /*
  19412. /* are expressly denied.                                             /*
  19413. /*                                                                   /*
  19414. /* Provided this copyright notice is included, this software may     /*
  19415. /* be freely distributed and not offered for sale.                   /*
  19416. /*                                                                   /*
  19417. /* Changes or modifications may be made and used only by the maker   /*
  19418. /* of same, and not further distributed.  Such modifications should  /*
  19419. /* be mailed to the author for consideration for addition to the     /*
  19420. /* software and incorporation in subsequent releases.                /*
  19421. /*                                                                   /*
  19422.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  19423. )BODY WINDOW(77,10)
  19424. +
  19425. %Command ===>^ZCMD
  19426. +
  19427. +Move cursor to choice (or type%S+next to choice) and press%ENTER+to select:
  19428. +
  19429. _A%1+- List%titles+of items in table
  19430. _B%2+- Log %text  +of items to%sequential file+
  19431. _C%3+- Log %text  +of items to%members of PDS+
  19432. +
  19433. +Press%&END (END)+to cancel the extract request.
  19434. )INIT
  19435.  .CURSOR = ZCMD
  19436.  &ZWINTTL = 'Extract Gopher items - titles or text'
  19437.  &END = PFK(END)
  19438.  &ZCMD = &Z
  19439.  &A = &Z
  19440.  &B = &Z
  19441.  &C = &Z
  19442. )PROC
  19443.  VER(&ZCMD,LIST,1,2,3)
  19444.  IF (&ZCMD ^= &Z)
  19445.   &GGCHOICE = TRANS(&ZCMD 1 1 2 2 3 3 * ?)
  19446.  ELSE
  19447.   &TEMP = '&A/&B/&C'
  19448.   IF (&TEMP = '//')
  19449.    &GGCHOICE = TRANS(.CURSOR A 1 B 2 C 3 * ?)
  19450.   ELSE
  19451.    &GGCHOICE = TRANS(&TEMP  'S//' 1
  19452.                             '1//' 1
  19453.                             '/S/' 2
  19454.                             '/2/' 2
  19455.                             '//S' 3
  19456.                             '//3' 3
  19457.                                * ?
  19458.                    )
  19459. )END
  19460. ./ ADD NAME=GGMPEXN1
  19461. )ATTR
  19462. /*                                                                   /*
  19463. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  19464. /*                                                                   /*
  19465. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  19466. /* including the implied warranties of merchantability and fitness,  /*
  19467. /* are expressly denied.                                             /*
  19468. /*                                                                   /*
  19469. /* Provided this copyright notice is included, this software may     /*
  19470. /* be freely distributed and not offered for sale.                   /*
  19471. /*                                                                   /*
  19472. /* Changes or modifications may be made and used only by the maker   /*
  19473. /* of same, and not further distributed.  Such modifications should  /*
  19474. /* be mailed to the author for consideration for addition to the     /*
  19475. /* software and incorporation in subsequent releases.                /*
  19476. /*                                                                   /*
  19477.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  19478. )BODY WINDOW(77,14)
  19479. +
  19480. %Command ===>^ZCMD
  19481. +
  19482. +Save to data set ===>_GGEXDSN
  19483.  
  19484. +(Note: Data set will be RECFM=VB, LRECL=259, BLKSIZE=6233.)
  19485.  
  19486. +Append to end of data set?   ===>_Z  +
  19487. +Blank line after separator?  ===>_Z  +
  19488. +Separator line between items (append mode only...blank for none):
  19489. +>^Z                                                                       +<
  19490.  
  19491. +Press%&END (END)+to cancel the extract request.
  19492. )INIT
  19493.  .ZVARS = '(GGEXAPP GGEXBLK GGEXSEP)'
  19494.  .CURSOR = GGEXDSN
  19495.  &ZWINTTL = 'Extract Gopher item listing'
  19496.  &END = PFK(END)
  19497.  &ZCMD = &Z
  19498.  VGET (GGEXDSN GGEXAPP GGEXBLK GGEXSEP) PROFILE
  19499.  &GGEXAPP = TRANS(&GGEXAPP Y,YES N,NO ' ',NO)
  19500.  &GGEXBLK = TRANS(&GGEXBLK Y,YES N,NO ' ',NO)
  19501. )PROC
  19502.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  19503.  VER(&GGEXDSN,NB,DSNAME)
  19504.  &GGEXAPP = TRUNC(&GGEXAPP,1)
  19505.  VER(&GGEXAPP,NB,LIST,Y,N)
  19506.  &GGEXBLK = TRUNC(&GGEXBLK,1)
  19507.  VER(&GGEXBLK,NB,LIST,Y,N)
  19508.  VPUT (GGEXDSN GGEXAPP GGEXBLK GGEXSEP) PROFILE
  19509. )END
  19510. ./ ADD NAME=GGMPEXOW
  19511. )ATTR
  19512. /*                                                                   /*
  19513. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  19514. /*                                                                   /*
  19515. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  19516. /* including the implied warranties of merchantability and fitness,  /*
  19517. /* are expressly denied.                                             /*
  19518. /*                                                                   /*
  19519. /* Provided this copyright notice is included, this software may     /*
  19520. /* be freely distributed and not offered for sale.                   /*
  19521. /*                                                                   /*
  19522. /* Changes or modifications may be made and used only by the maker   /*
  19523. /* of same, and not further distributed.  Such modifications should  /*
  19524. /* be mailed to the author for consideration for addition to the     /*
  19525. /* software and incorporation in subsequent releases.                /*
  19526. /*                                                                   /*
  19527.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  19528. )BODY WINDOW(58,10)
  19529. +
  19530. %Command ===>^ZCMD
  19531. +
  19532. +Dataset already exists:
  19533. +
  19534. %&GGEXDSN
  19535. +
  19536. +Press%ENTER+to%&ACTION
  19537. +Press%&END (END)+to cancel the request.
  19538. +
  19539. )INIT
  19540.  .ALARM = YES
  19541.  &ZWINTTL = 'Extract To Existing Data Set'
  19542.  &END = PFK(END)
  19543.  &APP = TRUNC(&GGEXAPP,1)
  19544.  IF (&APP = Y) &ACTION = 'append to the end of the data set.'
  19545.  ELSE          &ACTION = 'overwrite the current data set.'
  19546. )PROC
  19547.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  19548. )END
  19549. ./ ADD NAME=GGMPEXPW
  19550. )ATTR
  19551. /*                                                                   /*
  19552. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  19553. /*                                                                   /*
  19554. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  19555. /* including the implied warranties of merchantability and fitness,  /*
  19556. /* are expressly denied.                                             /*
  19557. /*                                                                   /*
  19558. /* Provided this copyright notice is included, this software may     /*
  19559. /* be freely distributed and not offered for sale.                   /*
  19560. /*                                                                   /*
  19561. /* Changes or modifications may be made and used only by the maker   /*
  19562. /* of same, and not further distributed.  Such modifications should  /*
  19563. /* be mailed to the author for consideration for addition to the     /*
  19564. /* software and incorporation in subsequent releases.                /*
  19565. /*                                                                   /*
  19566.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  19567. )BODY WINDOW(58,13)
  19568. +
  19569. %Command ===>^ZCMD
  19570. +
  19571. +Partitioned dataset already exists:
  19572. +
  19573. %&GGEXDSN
  19574. +
  19575. +If member names are generated that match existing members
  19576. +of this PDS, they will be%overwritten.+
  19577. +
  19578. +Press%ENTER+to proceed to use this PDS.
  19579. +Press%&END (END)+to cancel the request.
  19580. +
  19581. )INIT
  19582.  .ALARM = YES
  19583.  &ZWINTTL = 'Extract To Members of Existing PDS'
  19584.  &END = PFK(END)
  19585. )PROC
  19586.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  19587. )END
  19588. ./ ADD NAME=GGMPOPT
  19589. )ATTR
  19590. /*                                                                   /*
  19591. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  19592. /*                                                                   /*
  19593. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  19594. /* including the implied warranties of merchantability and fitness,  /*
  19595. /* are expressly denied.                                             /*
  19596. /*                                                                   /*
  19597. /* Provided this copyright notice is included, this software may     /*
  19598. /* be freely distributed and not offered for sale.                   /*
  19599. /*                                                                   /*
  19600. /* Changes or modifications may be made and used only by the maker   /*
  19601. /* of same, and not further distributed.  Such modifications should  /*
  19602. /* be mailed to the author for consideration for addition to the     /*
  19603. /* software and incorporation in subsequent releases.                /*
  19604. /*                                                                   /*
  19605.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  19606. )BODY WINDOW(77,10)
  19607. +
  19608. %Command ===>^ZCMD
  19609. +
  19610. +Move cursor to choice (or type%S+next to choice) and press%ENTER+to select:
  19611. +
  19612. _Z%1+- Display viewing options
  19613. _Z%2+- Other options
  19614. +
  19615. +Press%&END (END)+to return to the previous panel.
  19616. )INIT
  19617.  .ZVARS = '(S1 S2)'
  19618.  .CURSOR = ZCMD
  19619.  &ZWINTTL = 'Customize user options'
  19620.  &END = PFK(END)
  19621.  &ZCMD = &Z
  19622.  &S1   = &Z
  19623.  &S2   = &Z
  19624. )PROC
  19625.  IF (&ZCMD ^= &Z)
  19626.   &GGCHOICE = TRANS(&ZCMD 1 1 2 2 * ?)
  19627.  ELSE
  19628.   &TEMP = '&S1/&S2'
  19629.   IF (&TEMP = '/')
  19630.    &GGCHOICE = TRANS(.CURSOR S1 1 S2 2 * ?)
  19631.   ELSE
  19632.    &GGCHOICE = TRANS(&TEMP  'S/' 1
  19633.                             '1/' 1
  19634.                             '/S' 2
  19635.                             '/2' 2
  19636.                                * ?
  19637.                    )
  19638. )END
  19639. ./ ADD NAME=GGMPPRDS
  19640. )ATTR
  19641. /*                                                                   /*
  19642. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1993     /*
  19643. /*                                                                   /*
  19644. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  19645. /* including the implied warranties of merchantability and fitness,  /*
  19646. /* are expressly denied.                                             /*
  19647. /*                                                                   /*
  19648. /* Provided this copyright notice is included, this software may     /*
  19649. /* be freely distributed and not offered for sale.                   /*
  19650. /*                                                                   /*
  19651. /* Changes or modifications may be made and used only by the maker   /*
  19652. /* of same, and not further distributed.  Such modifications should  /*
  19653. /* be mailed to the author for consideration for addition to the     /*
  19654. /* software and incorporation in subsequent releases.                /*
  19655. /*                                                                   /*
  19656.  ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  19657.  #   TYPE(TEXT)  INTENS(LOW)
  19658.  @   TYPE(INPUT) INTENS(HIGH) CAPS(ON)  JUST(LEFT)
  19659. )BODY WINDOW(77,12)
  19660. +
  19661. %Command ===>^ZCMD
  19662. +
  19663. %&SUBJECT
  19664. +
  19665. +SYSOUT class ===>_Z+        Number of copies ===>_Z  +
  19666. #Destination  ===>@DESTUSR           #  Forms ===>@Z   #   UCS ===>@Z   +
  19667.  
  19668. +(Note: Print data will be released to SYSOUT immediately.)
  19669.  
  19670.  
  19671. +Press%&END (END)+to cancel the print request.
  19672. )INIT
  19673.  .ZVARS = '(GGEXSCL GGEXSCO GGEXSFO GGEXSUC)'
  19674.  .CURSOR = GGEXSCL
  19675.  &ZWINTTL = 'Print text'
  19676.  &SUBJECT = '&GGTSUBJ'
  19677.  &END = PFK(END)
  19678.  &ZCMD = &Z
  19679.  &GGEXSCO = 1
  19680.  &PVARS = 'GGEXSCL'
  19681.  IF (&GGALLPR ^= &Z)
  19682.   &PVARS = '&PVARS GGEXSDE GGEXSUS GGEXSFO GGEXSUC'
  19683.   .ATTRCHAR('#') = 'TYPE(TEXT)   INTENS(LOW)'
  19684.   .ATTRCHAR('@') = 'TYPE(INPUT)  INTENS(HIGH) CAPS(ON)  JUST(LEFT)'
  19685.  ELSE
  19686.   .ATTRCHAR('#') = 'TYPE(TEXT)   INTENS(NON)'
  19687.   .ATTRCHAR('@') = 'TYPE(OUTPUT) INTENS(NON)'
  19688.  VGET (&PVARS) PROFILE
  19689.  &DESTUSR = &GGEXSDE
  19690.  IF (&GGEXSDE ^= &Z)
  19691.   IF (&GGEXSUS ^= &Z)
  19692.    &DESTUSR = '&GGEXSDE..&GGEXSUS'
  19693. )PROC
  19694.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  19695.  VER(&GGEXSCL,NB)
  19696.  IF (&GGEXSCO = &Z) &GGEXSCO = 1
  19697.  VER(&GGEXSCO,NUM)
  19698.  VER(&GGEXSCO,RANGE,1,255)
  19699.  &GGEXSDE = TRUNC(&DESTUSR,'.')
  19700.  &GGEXSUS = .TRAIL
  19701.  VPUT (&PVARS) PROFILE
  19702. )END
  19703. ./ ADD NAME=GGMPWAIS
  19704. )ATTR
  19705. /*                                                                   /*
  19706. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  19707. /*                                                                   /*
  19708. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  19709. /* including the implied warranties of merchantability and fitness,  /*
  19710. /* are expressly denied.                                             /*
  19711. /*                                                                   /*
  19712. /* Provided this copyright notice is included, this software may     /*
  19713. /* be freely distributed and not offered for sale.                   /*
  19714. /*                                                                   /*
  19715. /* Changes or modifications may be made and used only by the maker   /*
  19716. /* of same, and not further distributed.  Such modifications should  /*
  19717. /* be mailed to the author for consideration for addition to the     /*
  19718. /* software and incorporation in subsequent releases.                /*
  19719. /*                                                                   /*
  19720.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  19721. )BODY WINDOW(58,10)
  19722. +
  19723. %Command ===>^ZCMD
  19724. +
  19725. +Enter index search query:
  19726. +
  19727. %===>^GGWAISQ
  19728.  
  19729. +Press%ENTER+to submit search request.
  19730. +Press%&END (END)+to cancel the request.
  19731. +
  19732. )INIT
  19733.  &ZWINTTL = 'GOPHER Full Text Index Search'
  19734.  &END = PFK(END)
  19735.  .CURSOR = GGWAISQ
  19736. )PROC
  19737.  IF  (&ZCMD ^= &Z) .MSG = ISPZ001
  19738.  VER (&GGWAISQ,NB)
  19739.  VPUT (GGWAISQ) PROFILE
  19740. )END
  19741. ./ ADD NAME=GGMPWHOI
  19742. )ATTR
  19743. /*                                                                   /*
  19744. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  19745. /*                                                                   /*
  19746. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  19747. /* including the implied warranties of merchantability and fitness,  /*
  19748. /* are expressly denied.                                             /*
  19749. /*                                                                   /*
  19750. /* Provided this copyright notice is included, this software may     /*
  19751. /* be freely distributed and not offered for sale.                   /*
  19752. /*                                                                   /*
  19753. /* Changes or modifications may be made and used only by the maker   /*
  19754. /* of same, and not further distributed.  Such modifications should  /*
  19755. /* be mailed to the author for consideration for addition to the     /*
  19756. /* software and incorporation in subsequent releases.                /*
  19757. /*                                                                   /*
  19758.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  19759. )BODY WINDOW(58,10)
  19760. +
  19761. %Command ===>^ZCMD
  19762. +
  19763. +Enter name to search for:
  19764. +
  19765. %===>^GGWHOISQ
  19766.  
  19767. +Press%ENTER+to submit search request.
  19768. +Press%&END (END)+to cancel the request.
  19769. +
  19770. )INIT
  19771.  &ZWINTTL = 'WHOIS/FINGER User Name Search'
  19772.  &END = PFK(END)
  19773.  .CURSOR = GGWHOISQ
  19774. )PROC
  19775.  IF  (&ZCMD ^= &Z) .MSG = ISPZ001
  19776.  VER (&GGWHOISQ,NB)
  19777.  VPUT (GGWHOISQ) PROFILE
  19778. )END
  19779. ./ ADD NAME=GGMVIEW
  19780. )ATTR DEFAULT(%+_)
  19781. /*                                                                   */
  19782. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1993     */
  19783. /*                                                                   */
  19784. /* This software is provided on an "AS IS" basis.  All warranties,   */
  19785. /* including the implied warranties of merchantability and fitness,  */
  19786. /* are expressly denied.                                             */
  19787. /*                                                                   */
  19788. /* Provided this copyright notice is included, this software may     */
  19789. /* be freely distributed and not offered for sale.                   */
  19790. /*                                                                   */
  19791. /* Changes or modifications may be made and used only by the maker   */
  19792. /* of same, and not further distributed.  Such modifications should  */
  19793. /* be mailed to the author for consideration for addition to the     */
  19794. /* software and incorporation in subsequent releases.                */
  19795. /*                                                                   */
  19796.  ^  TYPE(INPUT)  INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  19797.  #  TYPE(OUTPUT) INTENS(HIGH) CAPS(OFF) JUST(RIGHT)
  19798.  \  TYPE(OUTPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  19799.  |  AREA(DYNAMIC) EXTEND(ON) SCROLL(ON) USERMOD(05)
  19800.  01 TYPE(DATAOUT) INTENS(LOW)
  19801.  02 TYPE(DATAOUT) INTENS(HIGH)
  19802.  03 TYPE(DATAIN)  INTENS(LOW)
  19803.  04 TYPE(DATAIN)  INTENS(HIGH)
  19804. )BODY
  19805. \GGBTITLE
  19806. %COMMAND ===>^ZCMD                                            %SCROLL ===>_Z   +
  19807. |GGBDYNA                                                                       |
  19808. )INIT
  19809.  .ZVARS = GGMBROSC
  19810.  IF (&GGMBROSC = &Z) &GGMBROSC = CSR
  19811.  .CURSOR = &GGBCUR
  19812.  .CSRPOS = &GGBPOS
  19813. )PROC
  19814.  &GGBCUR = .CURSOR
  19815.  &GGBPOS = .CSRPOS
  19816.  &GGBLVL = LVLINE(GGBDYNA)
  19817.  VPUT (GGMBROSC) PROFILE
  19818. )END
  19819. ./ ENDUP
  19820. ?!
  19821.